Contextualizing Virtual Machines 3.8

The only requirement for OpenNebula Virtual Machine guests is that they need to be able to configure their network. The easiest way to accomplish this is deploying a Virtual Router and DHCP server inside each Virtual Network.

Alternatively, the OS can be contextualized to be able to:

This guide describes how to install and use the generic contextualization.

inlinetoc

Generic Contextualization Overview

When OpenNebula assigns an IP address to a network interface, the MAC address is set to MAC_PREFFIX:IP. This way the VM can know the assigned IP without an external DHCP server. For example, with the default mac prefix 02:00:

IP  = 192.169.0.118
MAC = 02:00:c0:a9:00:76

To configure other networking parameters, like the gateway or the network mask, OpenNebula provides a generic contextualization mechanism. The method we provide to present configuration parameters to a newly started virtual machine is using an ISO image (OVF recommendation). This method is network agnostic, making it suitable to configure network interfaces. In the VM description file you can specify the contents of the ISO file (files and directories), set the device where the ISO image will be accessible from, and specify the configuration parameters that will be written to a file for later use inside the virtual machine.

In this image we see a Virtual Machine with two associated disks. The Disk Image holds the Operating System. The ISO image is dynamically created by OpenNebula, and contains the contextualization for that VM:

  • context.sh: file that contains configuration variables, filled by OpenNebula with the parameters specified in the VM Template
  • init.sh: script called by the VM at start time, if it exists

The other files, certificates and service.conf are shown as an example of how any files can be included in the context ISO. They could contain files needed by the init.sh script

FIXME:

:!: To prevent regular users to copy system/secure files, the FILES attribute within CONTEXT is only allowed to OpenNebula users within the oneadmin group.

Preparing the Virtual Machine Image

To enable a Virtual Machine guest to use the contextualization ISO, it needs a series of scripts that will be executed at startup.

You can use the images available in the Marketplace, that are already prepared, or prepare your own images.

Linux Packages

There are two packages available:

  • Debian: Compatible with Ubuntu 11.10/12.04 and Debian Squeeze
  • CentOS: Compatible with CentOS and RHEL 6.x

If your distribution is not supported, see the Generating Custom Contextualization Packages section below to learn how to customize these packages or port them to other distributions.

After the installation is done, the VM on start will configure the network using the mac address generated by OpenNebula. They will also try to mount the cdrom context image from /dev/cdrom and if init.sh is found it will be executed.

Windows Scripts

The OpenNebula community has contributed scripts to contextualize Windows VMs. You can find more information in this blog post, and download the scripts from the IEETA wiki.

Preparing the VM Template

The VM Template contains a CONTEXT section where you can put arbitrary attributes, or reference other resource's template. These attributes will be written in the context.sh file.

There are some predefined attributes that the contextualization scripts will make use of:

Attribute Description
<DEV>_IP IP assigned to the interface
<DEV>_NETWORK Interface network
<DEV>_MASK Interface net mask
<DEV>_GATEWAY Interface gateway
<DEV>_DNS DNS servers for the network
DNS main DNS server for the machine
SSH_PUBLIC_KEY public ssh key added to root's authorized_keys

Let's see a brief example. Given these two Virtual Networks:

Public:

NAME = public
NETWORK_ADDRESS = 130.10.0.0
NETWORK_MASK = 255.255.255.0
GATEWAY = 130.10.0.1
DNS = "8.8.8.8 8.8.4.4"

Private:

NAME = private
NETWORK_ADDRESS = 10.0.0.0
NETWORK_MASK = 255.255.0.0

We can configure both network interfaces adding this context section to the VM template:

NIC = [ NETWORK = "public"]
NIC = [ NETWORK = "private"]
 
CONTEXT = [
  ETH0_IP      = "$NIC[IP, NETWORK=\"public\"]",
  ETH0_NETWORK = "$NETWORK[NETWORK, NETWORK=\"public\"]",
  ETH0_MASK    = "$NETWORK[MASK, NETWORK=\"public\"]",
  ETH0_GATEWAY = "$NETWORK[GATEWAY, NETWORK=\"public\"]",
  ETH0_DNS     = "$NETWORK[DNS, NETWORK=\"public\"]",
 
  ETH1_IP      = "$NIC[IP, NETWORK=\"private\"]",
  ETH1_NETWORK = "$NETWORK[NETWORK, NETWORK=\"private\"]",
  ETH1_MASK    = "$NETWORK[MASK, NETWORK=\"private\"]",
 
  SSH_PUBLIC_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+vPFFwem49zcepQxsyO51YMSpuywwt6GazgpJe9vQzw3BA97tFrU5zABDLV6GHnI0/ARqsXRX1mWGwOlZkVBl4yhGSK9xSnzBPXqmKdb4TluVgV5u7R5ZjmVGjCYyYVaK7BtIEx3ZQGMbLQ6Av3IFND+EEzf04NeSJYcg9LA3lKIueLHNED1x/6e7uoNW2/VvNhKK5Ajt56yupRS9mnWTjZUM9cTvlhp/Ss1T10iQ51XEVTQfS2VM2y0ZLdfY5nivIIvj5ooGLaYfv8L4VY57zTKBafyWyRZk1PugMdGHxycEh8ek8VZ3wUgltnK+US3rYUTkX9jj+Km/VGhDRehp user@host"
]

Remember to change the name of the network in the context section. If you add more that one interface to a Virtual Machine you can add the same parameters changing ETH0 to ETH1, ETH2, etc.

You can also add an `SSH_PUBLIC_KEY` parameter to the context to add an SSH public key to the root's `authorized_keys` file.

Now you are ready to run the Virtual Machine.

Reference

VM Template Context Section

In the VM template you can tell OpenNebula to create a contextualization image and to fill it with values using CONTEXT parameter. For example:

CONTEXT = [
  hostname   = "MAINHOST",
  ip_private = "$NIC[IP, NETWORK=\"public net\"]",
  dns        = "$NETWORK[DNS, NETWORK_ID=0]",
  root_pass  = "$IMAGE[ROOT_PASS, IMAGE_ID=3]",
  ip_gen     = "10.0.0.$VMID",
  files      = "/service/init.sh /service/certificates.$UID /service/service.conf"
]

Variables inside CONTEXT section will be added to context.sh file inside the contextualization image. These variables can be specified in three different ways:

  • Hardcoded variables:
hostname   = "MAINHOST"
  • Using template variables
    • $<template_variable>: any single value variable of the VM template, like for example:\\
      ip_gen     = "10.0.0.$VMID"
    • $<template_variable>[<attribute>]: Any single value contained in a multiple value variable in the VM template, like for example:
      ip_private = $NIC[IP]
    • $<template_variable>[<attribute>, <attribute2>=<value2>]: Any single value contained in a multiple value variable in the VM template, setting one attribute to discern between multiple variables called the same way, like for example:
      ip_public = "$NIC[IP, NETWORK=\"Public\"]"

      . You can use any of the attributes defined in the variable, NIC in the previous example.

  • Using Virtual Network template variables
  • $NETWORK[<vnet_attribute>, <NETWORK_ID|NETWORK>=<vnet_id|vnet_name>]: Any single value variable in the Virtual Network template, like for example:
    dns = "$NETWORK[DNS, NETWORK_ID=3]"

    Note that the network MUST be in used by any of the NICs defined in the template. The vnet_attribute can be TEMPLATE to include the whole vnet template in XML (base64 encoded).

  • Using Image template variables
  • $IMAGE[<image_attribute>, <IMAGE_ID|IMAGE>=<img_id|img_name>]: Any single value variable in the Image template, like for example:
    root = "$IMAGE[ROOT_PASS, IMAGE_ID=0]"

    Note that the image MUST be in used by any of the DISKs defined in the template. The image_attribute can be TEMPLATE to include the whole image template in XML (base64 encoded).

  • Using User template variables
    • $USER[<user_attribute>]: Any single value variable in the user (owner of the VM) template, like for example:
      ssh_key = "$USER[SSH_KEY]"

      The user_attribute can be TEMPLATE to include the whole user template in XML (base64 encoded).

  • Pre-defined variables, apart from those defined in the template you can use:
    • $UID, the uid of the VM owner
    • $TEMPLATE, the whole template in XML format and encoded in base64

The file generated will be something like this:

# Context variables generated by OpenNebula
hostname="MAINHOST"
ip_private="192.168.0.5"
dns="192.168.4.9"
ip_gen="10.0.0.85"
files="/service/init.sh /service/certificates.5 /service/service.conf"
target="sdb"
root="13.0"

Some of the variables have special meanings, but none of them are mandatory:

Attribute Description
files Files and directories that will be included in the contextualization image
target device where the contextualization image will be available to the VM instance. Please note that the proper device mapping may depend on the guest OS, e.g. ubuntu VMs should use hd* as the target device

:!: A default target attribute is generated automatically by OpenNebula, based on the default device prefix set at oned.conf.

Generating Custom Contextualization Packages

Network configuration is a script located in /etc/one-context.d/00-network. Any file located in that directory will be executed on start, in alphabetical order. This way we can add any script to configure or start processes on boot. For example, we can have a script that populates authorized_keys file using a variable in the context.sh. Remember that those variables are exported to the environment and will be easily accessible by the scripts:

#!/bin/bash
echo "$SSH_PUBLIC_KEY" > /root/.ssh/authorized_keys

OpenNebula source code comes with the scripts and the files needed to generate contextualization packages. This way you can also generate custom packages tweaking the scripts that will go inside your images or adding new scripts that will perform other duties.

The files are located in share/scripts/context-packages:

  • base: files that will be in all the packages. Right now it contains empty udev rules and the init script that will be executed on startup.
  • base_<type>: files specific for linux distributions. It contains the contextualization scripts for the network and comes in rpm and deb flavors. You can add here your own contextualization scripts and they will be added to the package when you run the generation script.
  • generate.sh: The script that generates the packages.
  • postinstall: This script will be executed after the package installation and will clean the network and udev configuration. It will also add the init script to the started services on boot.

To generate the packages you will need:

  • Ruby >= 1.8.7
  • gem fpm
  • dpkg utils for deb package creation
  • rpm utils for rpm package creation

You can also give to the generation script some parameters using env variables to generate the packages. For example, to generate an rpm package you will execute:

<xterm> $ PACKAGE_TYPE=rpm ./generate.sh </xterm>

These are the default values of the parameters, but you can change any of them the same way we did for PACKAGE_TYPE:

VERSION=3.7.80
MAINTAINER=C12G Labs <support@c12g.com>
LICENSE=Apache
PACKAGE_NAME=one-context
VENDOR=C12G Labs
DESCRIPTION="
This package prepares a VM image for OpenNebula:
  * Disables udev net and cd persistent rules
  * Deletes udev net and cd persistent rules
  * Unconfigures the network
  * Adds OpenNebula contextualization scripts to startup
 
To get support use the OpenNebula mailing list:
  http://opennebula.org/community:mailinglists
"
PACKAGE_TYPE=deb
URL=http://opennebula.org

For more information check the README.md file from that directory.