Python Libvirt Domain Configuration

So in my last article I talked a little bit about using libvirt to start and stop QEMU domains.

In this article I would like to go over how domains are created. QEMU uses XML files for each domain configuration, and using libvirt we can access that data.

First off lets connect to our local running QEMU instance:

>>> import libvirt
>>> conn = libvirt.open('qemu:///system')

Next lets look for and link to a running domain:

>>> conn.listDomainsID()
[35, 36, 37, 41, 38, 39]

>>> domain = conn.lookupByID(35)

The libvirt domain object gives os a function called XMLDesc() which we can use to see our running configuration:

>>> raw_xml = domain.XMLDesc(0)
>>> print raw_xml

<domain type='kvm' id='35'>
  <name>build01-dev</name>
  <uuid>c5c698cc-95bb-188d-3b5a-625asdj128sd</uuid>
  <memory>1048576</memory>
  <currentMemory>1048576</currentMemory>
  <vcpu>2</vcpu>
  <os>
    <type arch='x86_64' machine='fedora-13'>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/bin/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/mnt/data/libvirt/datastore01/data01-dev-clone-2.img'/>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    <disk type='file' device='cdrom'>
      <driver name='qemu' type='raw'/>
      <target dev='hdc' bus='ide'/>
      <readonly/>
      <alias name='ide0-1-0'/>
      <address type='drive' controller='0' bus='1' unit='0'/>
    </disk>
    <controller type='ide' index='0'>
      <alias name='ide0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <interface type='bridge'>
      <mac address='50:00:00:00:00:00'/>
      <source bridge='br1'/>
      <target dev='vnet0'/>
      <model type='e1000'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/0'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/0'>
      <source path='/dev/pts/0'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
    </input>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='5900' autoport='yes'/>
    <video>
      <model type='cirrus' vram='9216' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </memballoon>
  </devices>
</domain>

Now say you are interested in working with this XML data, we can do just that using the xml module:

>>> from xml.dom import minidom
>>> xml = minidom.parseString(raw_xml)

And something that may be useful in the XML above is the type tag, so lets grab that data:

>>> domainTypes = xml.getElementsByTagName('type')
>>> for domainType in domainTypes:
...   print domainType.getAttribute('machine')
...   print domainType.getAttribute('arch')
...
fedora-13
x86_64

And there you have it, we can easily pull out data from this XML using the minidom function.

Using this data it should be pretty easy to deploy a new guest domain using the createXML function:

Help on method createXML in module libvirt:

createXML(self, xmlDesc, flags) method of libvirt.virConnect instance
    Launch a new guest domain, based on an XML description similar
    to the one returned by virDomainGetXMLDesc()
    This function may require privileged access to the hypervisor.
    The domain is not persistent, so its definition will disappear when it
    is destroyed, or if the host is restarted (see virDomainDefineXML() to
    define persistent domains).

    If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
    will be started, but its CPUs will remain paused. The CPUs
    can later be manually started using virDomainResume.

    If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
    domain will be automatically destroyed when the virConnectPtr
    object is finally released. This will also happen if the
    client application crashes / loses its connection to the
    libvirtd daemon. Any domains marked for auto destroy will
    block attempts at migration, save-to-file, or snapshots.