Using CentOS Cloud Images with Virsh and Nuage Metadata

The following tools will help you to create virsh domains from CentOS Cloud images (those images can be downloaded from http://cloud.centos.org/centos/7/images). The script was based on Giovanni’s Post: Create a Linux Lab on KVM Using Cloud Images.

I am adding Nuage metadata into the XML to connect this domain to our VRS. After this process you may manage connectivity, ACLs, forwarding from the Nuage VSD console.

I am not bringing details how to install VRS into the KVM node. This is something that has already happened and is up and running. Check out my previous posts about how to do that. Also, libvirtd is up and running with no issues. You may find tons of notes how to install KVM over internet.

Prepare scripts, folders and templates

First of all, you will have to create the IMAGE dir. This case I am using “/root/virt/images”. Inside this folder you’ll copy your Centos7 and ISO images.
Download you Centos Cloud QCOW2 Image as you wish to your user folder (i.e. you may use wget or curl -i ). I’m using centos7-cloud-reverse-root.qcow2 in my case.

cloud-init will take the parameters from a cdrom image. We’ll create this cdrom iso over the script and set parameters like hostname and public key for the ssh connection to user “centos”. Then, you will need to get the string from your id_rsa.pub file in your .ssh folder.

Also, you have to create your script “virsh_create.sh” and bring the permissions to execute it (i.e. chmod 755 virsh_create.sh). And also copy the tmp.xml file to “/root/virt/images”.

You will need to create a small python program call macgen.py as follow:

#!/usr/bin/python
# macgen.py script to generate a MAC address for guests on Xen
#
import random
#
def randomMAC():
	mac = [ 0x00, 0x16, 0x3e,
		random.randint(0x00, 0x7f),
		random.randint(0x00, 0xff),
		random.randint(0x00, 0xff) ]
	return ':'.join(map(lambda x: "%02x" % x, mac))
#
print randomMAC()

virsh_create script file

Create your domain and get it connected to our Nuage VRS using the following script.

#!/bin/bash

# Take one argument from the commandline: VM name
if ! [ $# -eq 6 ]; then
    echo "Usage: $0 <node-name> <nuage-enterprise> <nuage-user> <nuage-dom> <nuage-zone> <nuage-subnet>"
    exit 1
fi

# Check if domain already exists
virsh dominfo $1 > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
    echo -n "[WARNING] $1 already exists.  "
    read -p "Do you want to overwrite $1 [y/N]? " -r
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        echo ""
    else
        echo -e "\nNot overwriting $1. Exiting..."
        exit 1
    fi
fi

# Directory to store images
DIR=~/virt/images

# Location of cloud image
IMAGE=$DIR/centos7-cloud-reverse-root.qcow2

# Amount of RAM in MB
MEM=1262144

# Number of virtual CPUs
CPUS=1

# Cloud init files
USER_DATA=user-data
META_DATA=meta-data
CI_ISO=$1-cidata.iso
DISK=$1.qcow2
MAC=`~/macgen.py`
UUID=`uuidgen`
TAP="tap-${UUID:0:11}"

# Start clean
rm -rf $DIR/$1
mkdir -p $DIR/$1

pushd $DIR/$1 > /dev/null

    # Create log file
    touch $1.log

    echo "$(date -R) Destroying the $1 domain (if it exists)..."

    # Remove domain with the same name
    virsh destroy $1 >> $1.log 2>&1
    virsh undefine $1 >> $1.log 2>&1
    rm  ./$1.xml >> $1.log 2>&1 

    # cloud-init config: set hostname, remove cloud-init package,
    # and add ssh-key 
    cat > $USER_DATA << _EOF_
#cloud-config

# Hostname management
preserve_hostname: False
hostname: $1
fqdn: $1.example.local

# Remove cloud-init when finished with it
runcmd:
  - [ yum, -y, remove, cloud-init ]

# Configure where output will go
output: 
  all: ">> /var/log/cloud-init.log"

# configure interaction with ssh server
ssh_svcname: ssh
ssh_deletekeys: True
ssh_genkeytypes: ['rsa', 'ecdsa']

# Install my public ssh key to the first user-defined user configured 
# in cloud.cfg in the template (which is centos for CentOS cloud images)
ssh_authorized_keys:
  - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBil2QzORhDcnKiVVNpO5daOSYVp8nshcIc7aTEkdlqCRir2Oni8BEStK7x7bvh0jrp9KptlHPeos87fQs//VXEb1FEprL2c6fPWmVdtjmYw3yzSkaFKMksL7FdUoEiwF6t8pQAg2mU0Qj9emSHBKg5ttdGqNoSvXc92k7iOzgauda7jdNak+Dx9dPhR3FJwHMcZSlQHO4cweZcK63bZitxlFkJ/FJdry/TBirDhRcXslOJ3ECU2xiyRXJVPs3VNLjMdOTTAoMmZj+GraUBbQ9VIqe683xe02sM83th5hj2C4gW3qXUoFkNLfKAMRxXLRMEwI3ABFB/AAUhACxyTJp giovanni@throwaway
_EOF_

    echo "instance-id: $1; local-hostname: $1" > $META_DATA

    echo "$(date -R) Copying template image..."
    cp $IMAGE $DISK

    # Create CD-ROM ISO with cloud-init config
    echo "$(date -R) Generating ISO for cloud-init..."
    genisoimage -output $CI_ISO -volid cidata -joliet -r $USER_DATA $META_DATA &>> $1.log

    echo "$(date -R) Installing the domain and adjusting the configuration..."
    echo "[INFO] Installing with the following parameters:"
    echo "Instance Name: ${1}"
    echo "Nuage Enterprise: ${2}"
    echo "Nuage Domain: ${4}"
    echo "Nuage Zone: ${5}"
    echo "Nuage Subnet: ${6}"
    echo "Nuage Enterprise: ${2}"
    echo "Instance MAC Address: ${MAC}"
    echo "Instance UUID Net Port: ${UUID}"
    echo "Instance tap interface: ${TAP}"
    echo "Instance Memory: ${MEM}"
    echo "Instance CPUs: ${CPU}"

    
    cat $DIR/tmp.xml | sed "s/%%name%%/${1}/" | sed "s/%%nuage_dom%%/${4}/" | sed "s/%%nuage_enterprise%%/${2}/" | sed "s/%%nuage_subnet%%/${6}/" |  \
    sed "s/%%nuage_user%%/${3}/" | sed "s/%%nuage_zone%%/${5}/" | sed "s/%%memory%%/${MEM}/" | sed "s/%%cpu%%/${CPUS}/" | sed "s/%%uuid%%/${UUID}/" |   \
    sed "s/%%tap-id%%/${TAP}/" | sed "s/%%cdrom%%/${1}\/${CI_ISO}/" | sed "s/%%image%%/${1}\/${DISK}/" | sed "s/%%mac%%/${MAC}/" > $1.xml

    virsh define $1.xml
    virsh start $1
#    virsh console $1
    
exit

You may run this as follow:

./virsh_create.sh test-01 "ACME Corp" mau dom2 zone0 subnet1

You may add the following lines to remove the media after the domain creation. I didn’t test it yet. It’s your call.

    sleep 30

    # Eject cdrom
    echo "$(date -R) Cleaning up cloud-init..."
    virsh change-media $1 hda --eject --config >> $1.log

    #Remove the unnecessary cloud init files
    rm $USER_DATA $CI_ISO

    echo "$(date -R) DONE. SSH to $1 using $IP, with  username 'centos'."

popd > /dev/null

tmp.xml: XML temporal file

This file have to be copied into IMAGE folder.

<domain type='kvm' >
  <name>%%name%%</name>
  <metadata>
    <nuage xmlns="http://www.nuagenetworks.net/2013/Vm/Metadata">
      <user name="%%nuage_user%%"/>
      <enterprise name="%%nuage_enterprise%%"/>
      <nuage_network domain="%%nuage_dom%%" type="ipv4" name="%%nuage_subnet%%" zone="%%nuage_zone%%">
        <interface mac="%%mac%%"/>
      </nuage_network>
    </nuage>
  </metadata>
  <memory unit='KiB'>%%memory%%</memory>
  <currentMemory unit='KiB'>%%memory%%</currentMemory>
  <vcpu placement='static'>%%cpu%%</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode='custom' match='exact'>
    <model fallback='allow'>qemu64</model>
  </cpu>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/root/virt/images/%%image%%'/>
      <backingStore/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <source file='/root/virt/images/%%cdrom%%'/>
      <backingStore/>
      <target dev='hda' bus='ide'/>
      <readonly/>
      <alias name='ide0-0-0'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>
    <controller type='usb' index='0' model='ich9-ehci1'>
      <alias name='usb0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <alias name='usb0'/>
      <master startport='0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <alias name='usb0'/>
      <master startport='2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <alias name='usb0'/>
      <master startport='4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <controller type='ide' index='0'>
      <alias name='ide0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='virtio-serial' index='0'>
      <alias name='virtio-serial0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </controller>
    <interface type='bridge'>
      <mac address='%%mac%%'/>
      <source bridge='alubr0'/>
      <virtualport type='openvswitch'>
        <parameters interfaceid='%%uuid%%'/>
      </virtualport>
      <target dev='%%tap-id%%'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <channel type='unix'>
      <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/%%name%%.org.qemu.guest_agent.0'/>
      <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/>
      <alias name='channel0'/>
      <address type='virtio-serial' controller='0' bus='0' port='1'/>
    </channel>
    <channel type='spicevmc'>
      <target type='virtio' name='com.redhat.spice.0' state='disconnected'/>
      <alias name='channel1'/>
      <address type='virtio-serial' controller='0' bus='0' port='2'/>
    </channel>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <input type='keyboard' bus='ps2'/>
    <graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
      <listen type='address' address='127.0.0.1'/>
      <image compression='off'/>
    </graphics>
    <sound model='ich6'>
      <alias name='sound0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </sound>
    <video>
      <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <redirdev bus='usb' type='spicevmc'>
      <alias name='redir0'/>
    </redirdev>
    <redirdev bus='usb' type='spicevmc'>
      <alias name='redir1'/>
    </redirdev>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </memballoon>
  </devices>
</domain>

See you around!

2 thoughts on “Using CentOS Cloud Images with Virsh and Nuage Metadata

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s