OpenNebula and Foreman integration

Our team is in the process of rearchitecting the test and develop infrastructure and we needed a way to easily install new OSs. This installation will be done in both physical nodes and Virtual Machines. To do this we selected The Foreman as the installation server.

For physical nodes we use the standard foreman workflow where we add a new host, select its OS and install the OS. For virtual machines we wanted it to be a bit more flexible and control it from OpenNebula itself. The idea is to configure the different operating systems in foreman and let our developers select the OS that was going to be installed in the machine.

To do this we have a hook that is able to communicate with foreman and register new hosts in foreman when a VM with certain parameters is created. The parameters that we can add in the template are these ones:

  • FOREMAN_OS_ID: Operating System identifier in foreman
  • FOREMAN_SUBNET: Network where the VM is going to start

The subnet is provided as we have two networks in our infrastructure. The hook will only run when FOREMAN_OS_ID is found in the template.

This is the hook we have added to OpenNebula. Bear in mind that this is a work in progress and we want to make it more straight forward for the user, like selecting the OS by its name and not a number.

#!/usr/bin/env ruby

# Add OpenNebula ruby library path. Alternatively you can install OpenNebula
# ruby gem
$: << '/usr/lib/one/ruby'

require 'rubygems'
require 'foreman_api'
require 'opennebula'
require 'base64'
require 'rexml/document'

# Parameters received by the hook from OpenNebula
ID=ARGV[0]
TEMPLATE_ENCODED=ARGV[1]

# Log file for script debugging
LOG=File.open('/tmp/hook.log', 'w+')

# Change your credentials and endpoint here
CREDENTIALS={
    :base_url => 'http://foreman',
    :username => 'admin',
    :password => 'amazingly_strong_password'
}

# In our infrastructure we have two network, here are the IDs of these networks
# in foreman
SUBNETS={
    'building'  => 1,
    'internal'  => 2
}

# There are some values hardcoded for the VMs as we don't use many different
# parameters but these can also be changed
def create_foreman_host(params ={})
    host = ForemanApi::Resources::Host.new(CREDENTIALS)

    description={
        "host" => {
            :name               => params[:name],
            :mac                => params[:mac],
            :ip                 => params[:ip],
            :architecture_id    => 1,   # x86_64
            :environment_id     => 1,   # production
            :domain_id          => 1,   # local
            :subnet_id          => params[:subnet_id],
            :operatingsystem_id => params[:os_id].to_i,
            :puppet_proxy_id    => 1,   # Only one proxy
            :hostgroup_id       => 1,   # We only have one hostgroup
            :build              => 1,   # Enable VM building
            :ptable_id          => params[:ptable_id],
            :medium_id          => params[:medium_id]
        }
    }

    host.create(description)
end

def get_foreman_os(id)
    os = ForemanApi::Resources::OperatingSystem.new(CREDENTIALS)
    res =  os.index

    res[0].select {|o| o["operatingsystem"]["id"]==id }[0]["operatingsystem"]
end

@client=OpenNebula::Client.new

template_decoded=Base64.decode64(TEMPLATE_ENCODED)
xml=Nokogiri::XML(template_decoded)

vm=OpenNebula::VirtualMachine.new(xml, @client)

LOG.puts vm.inspect

os_id=vm['VM/USER_TEMPLATE/FOREMAN_OS_ID']
subnet_name=vm['VM/USER_TEMPLATE/FOREMAN_SUBNET']

# We only execute the hook when FOREMAN_OS_ID is set in the VM template
exit(0) if !os_id

os=get_foreman_os(os_id.to_i)

# We need to fill medium and ptable values from OS parameters as Foreman uses
# the values from the hostgroup
medium=os['media'][0]['medium']['id']
ptable=os['ptables'][0]['ptable']['id']

subnet=1

subnet=SUBNETS[subnet_name] if SUBNETS[subnet_name]

# Fill VM parameters
info={
    :name   => vm['VM/NAME'],
    :ip     => vm['VM/TEMPLATE/NIC/IP'],
    :mac    => vm['VM/TEMPLATE/NIC/MAC'],
    :subnet_id  => subnet,
    :os_id  => os_id,
    :medium_id => medium,
    :ptable_id => ptable
}

LOG.puts create_foreman_host(info).inspect

# Chill out a bit an let foreman do its job
sleep 5

vm=OpenNebula::VirtualMachine.new(
    OpenNebula::VirtualMachine.build_xml(ID), @client)

# Release the VM hold so it can start
LOG.puts vm.release.inspect

This hook requires foreman_api gem. Now we add this hook to OpenNebula configuration with this stanza:

VM_HOOK = [
   name      = "foreman-create",
   on        = "CREATE",
   command   = "/var/lib/one/foreman_create_hook.rb",
   arguments = "$ID $TEMPLATE" ]

Now to create new VMs we have created an empty qcow2 image that will be used as the disk for new VMs. Making them qcow2 will let us clone them very fast and will be much smaller. We also have a template for all the VMs, something like this:

OS=[
  ARCH="x86_64",
  BOOT="network" ]

CPU="1"
MEMORY="768"

DISK=[
  IMAGE="empty_10gb_disk" ]
NIC=[
  NETWORK="building" ]

GRAPHICS=[
  LISTEN="0.0.0.0",
  TYPE="vnc" ]

FOREMAN_OS_ID="2"           # in our case this is a Ubuntu 12.10
FOREMAN_SUBNET="building"

The VM should be launched on hold so we have time to add the host to foreman and configuring DHCP and TFTP servers. At this time we can only do this using the CLI:

$ onetemplate instantiate foreman-base --hold

We can also change the OS to be installed without changing the template

$ onetemplate instantiate foreman-base --hold --raw FOREMAN_OS_ID=1

After the VM is created the hook kicks in, adds the new host to foreman and releases the VM from hold so it can start and be installed. When the installation procedure is finished we can start using the VM or capture it so we can use as a base for other VMs. To do this we can use a disk snapshot (not hot) and shutdown the machine to save the new image.

Things to take into account:

  • Add installation of OpenNebula contextualization packages in the Foreman templates so the images are ready to be used in OpenNebula
  • Configure puppet, chef or other CMS so the images can serve as basis for your app deployments

Features we want to add to the integration:

  • Select OS by name, not id
  • Select the subnet from the OpenNebula network so it does not need to be specified
  • Automatically hold the VM on startup so Sunstone can be used to install new VMs
  • New hook to delete the host from foreman after it is deleted in OpenNebula

You can find the code from this post in this gist.

Start Your New OpenNebula User Group!

The OpenNebula Project is happy to announce the support for the creation and operation of OpenNebula User Groups. An OpenNebula User Group is a gathering of our users in a local area to share best practices, discuss technical questions, network, and learn from each other.

If you are a passionate OpenNebula user and are interested in starting your own OpenNebula User Group, join our Community Discuss mailing list and let us know about your plans.

There is more information in the new User Groups section of our site.

We look forward to your User Group proposal!

Command Line Tweaks for OpenNebula 4.0

In the last post we’ve seen the beautiful new face of Sunstone. Even if we are putting lots of effort in the web interface we are also giving some love to the command line interface.

Until now the creation of images and templates from the command line consisted on creating a template file and feeding it to oneimage/onetemplate create command. There still exist that possibility but we can create simple images or VM templates using just command parameters.

For example, registering an image can be done with this command:

$ oneimage create -d default --name ttylinux \
--path http://marketplace.c12g.com/appliance/4fc76a938fb81d3517000003/download
ID: 4

You can also pass a file to the path, but take into account that you need to configure the datastores SAFE_DIRS parameter to make it work.

We can also create image from scratch, for example, a raw image of 512 Mb that will be connected using virtio:

$ oneimage create --name scratch --prefix vd --type datablock --fstype raw \
--size 512m -d default
ID: 5

You can get more information on the parameters issuing oneimage create --help.

Creation of VM templates is also very similar. For example, creating a VM that uses both disks and a network, adding contextualization options and enabling VNC:

$ onetemplate create --name my_vm --cpu 4 --vcpu 4 --memory 16g \
--disk ttylinux,scratch --network network --net_context --vnc
ID: 1
$ onetemplate instantiate my_vm
VM ID: 10

The output of onevm show was also changed to show disks and nics in an easier to read fashion:

$ onevm show 10
VIRTUAL MACHINE 10 INFORMATION
ID : 10
NAME : my_vm-10

[...]

VM DISKS
 ID TARGET IMAGE                               TYPE SAVE SAVE_AS
  0    hda ttylinux                            file   NO       -
  1    vda scratch                             file   NO       -

VM NICS
 ID NETWORK                                IP               MAC VLAN BRIDGE
  0 network                       192.168.0.8 02:00:c0:a8:00:08   no vbr0

VIRTUAL MACHINE TEMPLATE
CONTEXT=[
  DISK_ID="2",
  ETH0_DNS="192.168.0.1",
  ETH0_GATEWAY="192.168.0.1",
  ETH0_IP="192.168.0.8",
  ETH0_MASK="255.255.255.0",
  TARGET="hdb" ]
CPU="4"
GRAPHICS=[
  LISTEN="0.0.0.0",
  PORT="5910",
  TYPE="vnc" ]
MEMORY="16384"
TEMPLATE_ID="1"
VCPU="4"
VMID="10"

This way you can get useful information about the VM in just a glimpse. If you need more information you can still use -x option or the new --all, this will print all the information in the template a the previous versions.

oneimage show was also changed so you can check which VMs are using an image:

$ oneimage show scratch
IMAGE 5 INFORMATION
ID : 5
NAME : scratch

[...]

VIRTUAL MACHINES

ID USER     GROUP    NAME            STAT UCPU    UMEM HOST             TIME
10 oneadmin oneadmin my_vm-10        pend    0      0K              0d 00h03
[/sourcecode]

This is also true for onevnet show:

$ onevnet show network
VIRTUAL NETWORK 0 INFORMATION
ID : 0
NAME : network

[...]

VIRTUAL MACHINES

ID USER     GROUP    NAME            STAT UCPU    UMEM HOST             TIME
 9 oneadmin oneadmin template1       pend    0      0K              0d 00h30
10 oneadmin oneadmin my_vm-10        pend    0      0K              0d 00h04

Another nice parameter is --dry. This parameter can be used with onetemplate and oneimage create. It will print the generated template but will not register it. It is useful when you want to create a complex template but don’t want to type it from scratch, just redirect it to a file and edit it to add some features not available from the command line.

One last thing, the parameters for onevm create are the exact same ones as onetemplate create. If you just want to create a fire and forget VM you can use onevm create the same way.

OpenNebula 4.0 will be available for testing, really soon. Until then, we will keep you updated with the new features in posts like this. You can also check the posts released in the last weeks about the Ceph integration, the new scheduling feature, and the new Sunstone.
Stay tuned!

New Contextualization Packages for OpenNebula 3.8

Some weeks ago with the creation of the OpenNebula Marketplace, we released contextualization packages to help prepare VM images. These packages did some work that previously we had to do manually:

  • Disable/delete udev net and cdrom persistent rules. On boot, linux distributions scan for new hardware and discovered network and cdrom are added to a file. This process is really useful for physical machines so adding or taking out a new network card wont change the name of the rest, making the configuration we had still useful. With virtual machines this is a nuisance. A simple MAC address change will make udev create a new device for that interface and the configuration will no longer be used.
  • Unconfigure network. This way the VM won’t configure the network before the OpenNebula contextualization kicks in.
  • Add contextualization scripts to startup. These scripts will configure the network and will call init.sh from the context cdrom enabling us to do some magic with the context section of the VM template.

One of the changes introduced in OpenNebula 3.8 is the new contextualization packages. The new version does the same as the previous one with some changes that we hope will make people creating images happier.

Modular Contextualization Scripts

Now the script launched on VM boot has less logic:

  • Mounts the context cdrom
  • Exports the variables from context.sh
  • Executes any script located in /etc/one-context.d
  • Executes init.sh from cdrom
  • Unmounts the cdrom

Network configuration is now 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 

 

Network Configuration Driven by Contextualization

The new network configuration scripts can still infer the network configuration from the MAC address of the VM, the same as the previous versions. The way OpenNebula generates MAC addresses by default is by setting the first 2 bytes of the MAC address to the prefix configured in oned.conf and the rest 4 bytes to the IP assigned. This method is convenient but lacks flexibility and some interesting parameters like the network mask or gateway information.

Other way we had to configure the network was adding a script to the contextualization cdrom using the file. This method is very flexible but most of the time we always configure the same network parameters so this script changes very rarely. Also, in new OpenNebula versions we discourage the use of contextualization file parameter as it can lead to security problems.

Now the network configuration script will search for some predefined environment variables to configure network parameters. The parameters are:

Attribute Description
<DEV>_IP IP assigned to the interface
<DEV>_NETWORK Interface network
<DEV>_MASK Interface net mask
<DEV>_GATEWAY Interface gateway

 

We will substitute <DEV> with the interface the variable refers to in uppercase, as in ETH0, ETH1, etc. As an example, we can have a network defined this way:

NAME=public
NETWORK_ADDRESS=80.0.0.0
NETWORK_MASK=255.255.255.0
GATEWAY=80.0.0.1

 

And then in the VM contextualization those parameters for eth0 can be expressed as:

CONTEXT=[
 ETH0_IP = "$NIC[IP, NETWORK=\"public\"]",
 ETH0_NETWORK = "$NIC[NETWORK_ADDRESS, NETWORK=\"public\"]",
 ETH0_MASK = "$NIC[NETWORK_MASK, NETWORK=\"public\"]",
 ETH0_GATEWAY = "$NIC[GATEWAY, NETWORK=\"public\"]"
]

 

Generation of Custom Contextualization Packages

OpenNebula source code comes with the scripts and the files needed to generate those 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 udevconfiguration. 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:

$ PACKAGE_TYPE=rpm ./generate.sh 

 

These are the default values of the parameters, but you can change any of them the same way we did forPACKAGE_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.

Contextualization Packages for VMs

We know that creating new Virtual Appliances can be sometimes cumbersome. To help you creating them a new set of packages were developed so the preparation of these images to work with OpenNebula is a breeze. They are compatible with:

  • Ubuntu >= 11.x
  • Debian Squeeze
  • CentOS 6.x
  • RHEL 6.x

These packages will prepare udev rules so you wont have problems after the first start and will also add the contextualization scripts to configure the network and any other subsystem or software using the contextualization CDROM.

More information in the Contextualization Packages for VM Images guide.

OpenNebula 1.4.0 released

The OpenNebula team is happy to announce that we have reached a stable state for the new 1.4 series of the OpenNebula Toolkit. During these months we have been working on new features that we hope will be helpful to manage your infrastructure. Downloads are available as source code as previous version but we also have created binary packages for RedHat/CentOS, Ubuntu, openSUSE and Fedora.

We want to thank the people actively using beta versions that provided us feedback to polish features and get rid of bugs before releasing this stable version.


Highlights of OpenNebula 1.4 are…

  • EC2 Query API interface for building OpenNebula-based clouds
  • OCCI interface for building OpenNebula-based clouds
  • Support for the VMware Hypervisor family
  • Multiple user support and access-right control for Virtual Machines and Virtual Networks
  • Advance contextualization support to integrate VM packs and implement multi-component services
  • Easy integration with your data-center services and procedures with a new hook system
  • Support block devices as VM images.
  • Support for LVM storage
  • Many bug fixes, and scalability and performance improvements in several components of the OpenNebula system
  • A whole new set of documentation pages, guides and examples

Quick Links

The OpenNebula Team!