Contextualizing Virtual Machines 1.4

Overview

The method we provide to give configuration parameters to a newly started virtual machine is using an ISO image (OVF recommendation). This method is network agnostic so it can be used also to configure network interfaces. In the VM description file you can specify the contents of the iso file (files and directories), tell the device the ISO image will be accessible and specify the configuration parameters that will be written to a file for later use inside the virtual machine.

In this example we see a Virtual Machine with two associated disks. The Disk Image holds the filesystem where the Operating System will run from. The ISO image has the contextualization for that VM:

  • context.sh: file that contains configuration variables, filled by OpenNebula with the parameters specified in the VM description file
  • init.sh: script called by VM at start that will configure specific services for this VM instance
  • certificates: directory that contains certificates for some service
  • service.conf: service configuration

:!: This is just an example of what a contextualization image may look like. Only context.sh is included by default. You have to specify the values that will be written inside context.sh and the files that will be included in the image.

Defining context

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

CONTEXT = [
  hostname   = "$NAME",
  ip_private = "$NIC[IP, NETWORK=\"Private LAN\"]",
  ip_gen     = "10.0.0.$VM_ID",
  files      = "/service/init.sh /service/certificates /service/service.conf",
  target     = "sdc"
]

Variables inside CONTEXT section will be added to context.sh file inside the contextualization image. The variables starting with $ are substituted by the values that this specific VM instance has (you can check the values with onevm show). In this case $NAME gets its value from the NAME specified in the VM description file. $NIC[IP, NETWORK=“Private LAN”] will get the IP assigned to the interface that associated to Private LAN network.

The file generated will be something like this:

# Context variables generated by OpenNebula
hostname="somename"
ip_private="192.168.0.5"
ip_gen="10.0.0.85"
files="/service/init.sh /service/certificates /service/service.conf"
target="sdc"

Some of the variables have special meanings:

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

Using Context

The VM should be prepared to use the contextualization image. First of all it needs to mount the contextualization image somewhere at boot time. Also a script that executes after boot will be useful to make use of the information provided.

The file context.sh is compatible with bash syntax so you can easilly source it inside a shellscript to get the variables that it contains.

EXAMPLE

Here we propose a way to use this contextualization data. Each unix has their own filesystem layout and way of handling init scripts, this examples assumes a debian-based virtual machine.

We are going to use contextualization data to set the hostname, the IP address and a user with known ssh keys.

First thing, lets outline the CONTEXT section of the VM template:

CONTEXT = [
  hostname  = "$NAME",
  ip_public = "$NIC[IP, NETWORK=\"Public\"]",
  username  = virtualuser
  files     = "/vms_configuration/id_rsa.pub /vms_configuration/init.sh",
  target    = "sdc"
]

The OpenNebula front-end will thus require a /vms_configuration folder with:

  • id_rsa.pub: Public ssh key to be added to the trusted ssh keys of the new user
  • init.sh: script that will perform the configuration. Explained below.

Now we will need to configure the VM to make use of this data. We are going to place in /etc/rc.local as:

#!/bin/sh -e
 
mount -t iso9660 /dev/sdc /mnt
 
if [ -f /mnt/context.sh ]; then
  . /mnt/init.sh
fi
 
umount /mnt
 
exit 0      

We use an indirection (rc.local calls init.sh) so changing the script means editing a file locally rather that changing it inside the VMs.

The init.sh script will be the one actually doing the work:

#!/bin/bash
 
if [ -f /mnt/context.sh ]; then
  . /mnt/context.sh
fi
 
hostname $HOSTNAME
ifconfig eth0 $IP_PUBLIC
 
useradd -m $USERNAME
 
mkdir -p ~$USERNAME/.ssh
cat /mnt/id_rsa.pub >> ~$USERNAME/.ssh/authorized_keys
 
chown -R $USERNAME /home/$USERNAME