Create new KVM guest from template

Most of us don’t like to install guest OS repeatedly, instead, we often install one guest OS, then do some setup and customization. After that, we make a backup of the disk image(We use it as a template). If we want to install the same OS later, we only need to copy that template disk image and create a new guest config file.

When create a new guest config file, we need to give it a unique name, a unique uuid, and a unique MAC address. Also, we need to change it’s disk file path. We can do this kind of changes manually, hower, according to the rule “automate all that can be automated”, we can use a script to do this.

Assume that we have a temaplate CentOS 5.6 guest, and here is its xml config file:
centos5.6.xml

<domain type='kvm'>
  <name>centos56</name>
  <uuid>f065c048-32a4-feb8-1702-78b8d828e450</uuid>
  <memory>524288</memory>
  <currentMemory>524288</currentMemory>
  <vcpu>2</vcpu>
  <os>
    <type arch='x86_64' machine='rhel6.0.0'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='/vmrepo/disk/centos5.6.img'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <interface type='bridge'>
      <mac address='52:54:00:88:d0:51'/>
      <source bridge='br1'/>
      <model type='virtio'/>
    </interface>
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target port='0'/>
    </console>
    <memballoon model='virtio'>
    </memballoon>
  </devices>
</domain>

We can create a new guest VM from this template like this:

./newvm.py --name lvs --config ./centos5.6.xml
#or this way: 
#./newvm.py -n lvs -c ./centos5.6.xml
#both the -n and -c option are required.

This will create a file named lvs.xml under the current directory. Because making a copy of the template disk make take a long time, and sometimes we may use lvm as disk. so this script will not create the disk image for us. Instead, it outputs the disk path it will use:

Created vm config file lvs.xml
Use disk image /vmrepo/disk/lvs.img, you must create it from the template disk: /vmrepo/disk/centos5.6.img
Done!

Notes:

  • The template xml config file may not include any pci addresses line, because different vm can not use the same PCI address, it will conflict
    eg:

    <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    

    lines like this must be removed from the template xml file.

  • you need to install the python-virtinst package for uuid generation. On CentOS/RHEL 5.x, which uses python 2.4, you need to install the python-lxml package(this package is in epel repo.)
    yum install python-virtinst
    yum install python-lxml #only on CentOS/RHEL 5.x
    

Here’s the script newvm.py


#!/usr/bin/python
# Used to create a vm from template
# By Curu Wong contact: prinbra(at)gmail(dot)com
import sys,os
from optparse import OptionParser
from virtinst.util import *
if sys.version_info < (2,5): import lxml.etree as ET else: import xml.etree.ElementTree as ET parser = OptionParser(); parser.add_option(“-n”, “–name”, dest=”name”, help=”VM name”); parser.add_option(“-c”, “–config”, dest=”config”, help=”Template VM XML config file”); (options, args) = parser.parse_args(); if not options.name or not options.config: print “Usage %s -n name -c template_xml” % sys.argv[0] sys.exit(1) config = ET.parse(options.config) vm_name = options.name name = config.find(‘name’) name.text = vm_name uuid = config.find(‘uuid’) uuid.text = uuidToString(randomUUID()) mac = config.find(‘devices/interface/mac’) mac.attrib[‘address’] = randomMAC(type=’qemu’) disk = config.find(‘devices/disk/source’) disk_old = disk.attrib[‘file’] disk_path = os.path.dirname(disk_old) disk_ext = os.path.splitext(disk_old)[1] disk_image = disk_path + ‘/’ + vm_name + disk_ext disk.attrib[‘file’] = disk_image if os.path.exists(vm_name + ‘.xml’): print “File %s.xml exists, abort” % vm_name sys.exit(1) config.write(vm_name + ‘.xml’) print “Created vm config file %s.xml” % vm_name print “Use disk image %s, you must create it from the template disk: %s” % (disk_image, disk_old) print “Done!” [/Python]

This entry was posted in Programming, Python, System Administration, Virtualization and tagged . Bookmark the permalink.