summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2012-03-07 08:39:07 -0500
committerDaniel P. Berrange <berrange@redhat.com>2012-03-23 19:23:12 +0000
commitf6bddbe4161bfb6ff02a807d5455c018c98d607d (patch)
tree32725e51fff7c195877032153a376222e2a0ec34
parent1c6fff4906eb7fd7af9cd507014bea20fb39b7d6 (diff)
Introduce a set of classes for storing libvirt guest configuration
With the current Cheetah template based approach to XML generation, there is never any canonical representation of the guest configuration. When generating XML, a hash is filled in with parameters to be used to generate XML, an even some pre-built XML snippets. When reading XML, typically XPath is used, but sometimes manual DOM traversal is used. This change introduces a set of classes for explicitly representing the guest configuration. They are intended to allow the guest config to be read/written using normal programatic APIs, avoiding the need for any code to know about XML. This first impl though, only supports writing of XML. The code to parse an existing XML doc is not yet written. The class hierarchy is as follows LibvirtConfigObject | + LibvirtConfigGuest + LibvirtConfigGuestDevice | +- LibvirtConfigGuestDisk +- LibvirtConfigGuestFilesys +- LibvirtConfigGuestInterface +- LibvirtConfigGuestInput +- LibvirtConfigGuestGraphics +- LibvirtConfigGuestChar | +- LibvirtConfigGuestSerial +- LibvirtConfigGuestConsole The base LibvirtConfigObject class provides some generic boilerplate code. Subclasses need to override the "format_dom" method for generating XML DOMS, and "parse_dom" for reading XML DOMs. The conversion from DOM <-> XML String is handled by the base class. The DOMs are based on the lxml.etree.Element class. * nova/tests/test_libvirt_config.py: Test cases for XML formatting of all config object classes * nova/virt/libvirt/config.py: Config object classes for libvirt guest XML schema blueprint libvirt-xml-config-apis Change-Id: I0474b6640b47ad0e5bb74503a5ff99a8a41bcdc4 Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
-rw-r--r--nova/tests/test_libvirt_config.py363
-rw-r--r--nova/virt/libvirt/config.py358
2 files changed, 721 insertions, 0 deletions
diff --git a/nova/tests/test_libvirt_config.py b/nova/tests/test_libvirt_config.py
new file mode 100644
index 000000000..186fb5a18
--- /dev/null
+++ b/nova/tests/test_libvirt_config.py
@@ -0,0 +1,363 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from lxml import etree
+from lxml import objectify
+
+from nova import test
+
+from nova.virt.libvirt import config
+
+
+class LibvirtConfigBaseTest(test.TestCase):
+ def assertXmlEqual(self, expectedXmlstr, actualXmlstr):
+ expected = etree.tostring(objectify.fromstring(expectedXmlstr))
+ actual = etree.tostring(objectify.fromstring(actualXmlstr))
+ self.assertEqual(expected, actual)
+
+
+class LibvirtConfigTest(LibvirtConfigBaseTest):
+
+ def test_config_plain(self):
+ obj = config.LibvirtConfigObject(root_name="demo")
+ xml = obj.to_xml()
+
+ self.assertXmlEqual(xml, "<demo/>")
+
+ def test_config_ns(self):
+ obj = config.LibvirtConfigObject(root_name="demo", ns_prefix="foo",
+ ns_uri="http://example.com/foo")
+ xml = obj.to_xml()
+
+ self.assertXmlEqual(xml, """
+ <foo:demo xmlns:foo="http://example.com/foo"/>""")
+
+ def test_config_text(self):
+ obj = config.LibvirtConfigObject(root_name="demo")
+ root = obj.format_dom()
+ root.append(obj._text_node("foo", "bar"))
+
+ xml = etree.tostring(root)
+ self.assertXmlEqual(xml, "<demo><foo>bar</foo></demo>")
+
+
+class LibvirtConfigGuestDiskTest(LibvirtConfigBaseTest):
+
+ def test_config_file(self):
+ obj = config.LibvirtConfigGuestDisk()
+ obj.source_type = "file"
+ obj.source_path = "/tmp/hello"
+ obj.target_dev = "/dev/hda"
+ obj.target_bus = "ide"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <disk type="file" device="disk">
+ <source file="/tmp/hello"/>
+ <target bus="ide" dev="/dev/hda"/>
+ </disk>""")
+
+ def test_config_block(self):
+ obj = config.LibvirtConfigGuestDisk()
+ obj.source_type = "block"
+ obj.source_path = "/tmp/hello"
+ obj.source_device = "cdrom"
+ obj.driver_name = "qemu"
+ obj.target_dev = "/dev/hdc"
+ obj.target_bus = "ide"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <disk type="block" device="cdrom">
+ <driver name="qemu"/>
+ <source dev="/tmp/hello"/>
+ <target bus="ide" dev="/dev/hdc"/>
+ </disk>""")
+
+ def test_config_network(self):
+ obj = config.LibvirtConfigGuestDisk()
+ obj.source_type = "network"
+ obj.source_protocol = "iscsi"
+ obj.source_host = "foo.bar.com"
+ obj.driver_name = "qemu"
+ obj.driver_format = "qcow2"
+ obj.target_dev = "/dev/hda"
+ obj.target_bus = "ide"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <disk type="network" device="disk">
+ <driver name="qemu" type="qcow2"/>
+ <source protocol="iscsi" name="foo.bar.com"/>
+ <target bus="ide" dev="/dev/hda"/>
+ </disk>""")
+
+
+class LibvirtConfigGuestFilesysTest(LibvirtConfigBaseTest):
+
+ def test_config_mount(self):
+ obj = config.LibvirtConfigGuestFilesys()
+ obj.source_type = "mount"
+ obj.source_dir = "/tmp/hello"
+ obj.target_dir = "/mnt"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <filesystem type="mount">
+ <source dir="/tmp/hello"/>
+ <target dir="/mnt"/>
+ </filesystem>""")
+
+
+class LibvirtConfigGuestInputTest(LibvirtConfigBaseTest):
+
+ def test_config_tablet(self):
+ obj = config.LibvirtConfigGuestInput()
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <input type="tablet" bus="usb"/>""")
+
+
+class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
+
+ def test_config_graphics(self):
+ obj = config.LibvirtConfigGuestGraphics()
+ obj.type = "vnc"
+ obj.autoport = True
+ obj.keymap = "en_US"
+ obj.listen = "127.0.0.1"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <graphics type="vnc" autoport="yes" keymap="en_US" listen="127.0.0.1"/>
+ """)
+
+
+class LibvirtConfigGuestSerialTest(LibvirtConfigBaseTest):
+
+ def test_config_file(self):
+ obj = config.LibvirtConfigGuestSerial()
+ obj.type = "file"
+ obj.source_path = "/tmp/vm.log"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <serial type="file">
+ <source file="/tmp/vm.log"/>
+ </serial>""")
+
+
+class LibvirtConfigGuestSerialTest(LibvirtConfigBaseTest):
+ def test_config_pty(self):
+ obj = config.LibvirtConfigGuestConsole()
+ obj.type = "pty"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <console type="pty"/>""")
+
+
+class LibvirtConfigGuestInterfaceTest(LibvirtConfigBaseTest):
+ def test_config_ethernet(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "ethernet"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.target_dev = "vnet0"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <interface type="ethernet">
+ <mac address="DE:AD:BE:EF:CA:FE"/>
+ <model type="virtio"/>
+ <target dev="vnet0"/>
+ </interface>""")
+
+ def test_config_bridge(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "bridge"
+ obj.source_dev = "br0"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.filtername = "clean-traffic"
+ obj.filterparams.append({"key": "IP", "value": "192.168.122.1"})
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <interface type="bridge">
+ <mac address="DE:AD:BE:EF:CA:FE"/>
+ <model type="virtio"/>
+ <source bridge="br0"/>
+ <filterref filter="clean-traffic">
+ <parameter name="IP" value="192.168.122.1"/>
+ </filterref>
+ </interface>""")
+
+ def test_config_bridge_ovs(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "bridge"
+ obj.source_dev = "br0"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.vporttype = "openvswitch"
+ obj.vportparams.append({"key": "instanceid", "value": "foobar"})
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <interface type="bridge">
+ <mac address="DE:AD:BE:EF:CA:FE"/>
+ <model type="virtio"/>
+ <source bridge="br0"/>
+ <virtualport type="openvswitch">
+ <parameters instanceid="foobar"/>
+ </virtualport>
+ </interface>""")
+
+ def test_config_8021Qbh(self):
+ obj = config.LibvirtConfigGuestInterface()
+ obj.net_type = "direct"
+ obj.mac_addr = "DE:AD:BE:EF:CA:FE"
+ obj.model = "virtio"
+ obj.source_dev = "eth0"
+ obj.vporttype = "802.1Qbh"
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <interface type="direct">
+ <mac address="DE:AD:BE:EF:CA:FE"/>
+ <model type="virtio"/>
+ <source mode="private" dev="eth0"/>
+ <virtualport type="802.1Qbh"/>
+ </interface>""")
+
+
+class LibvirtConfigGuestTest(LibvirtConfigBaseTest):
+
+ def test_config_lxc(self):
+ obj = config.LibvirtConfigGuest()
+ obj.virt_type = "lxc"
+ obj.memory = 1024 * 1024 * 100
+ obj.vcpus = 2
+ obj.name = "demo"
+ obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
+ obj.os_type = "exe"
+ obj.os_init_path = "/sbin/init"
+
+ fs = config.LibvirtConfigGuestFilesys()
+ fs.source_dir = "/root/lxc"
+ fs.target_dir = "/"
+
+ obj.add_device(fs)
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <domain type="lxc">
+ <uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
+ <name>demo</name>
+ <memory>104857600</memory>
+ <vcpu>2</vcpu>
+ <os>
+ <type>exe</type>
+ <init>/sbin/init</init>
+ </os>
+ <devices>
+ <filesystem type="mount">
+ <source dir="/root/lxc"/>
+ <target dir="/"/>
+ </filesystem>
+ </devices>
+ </domain>""")
+
+ def test_config_xen(self):
+ obj = config.LibvirtConfigGuest()
+ obj.virt_type = "xen"
+ obj.memory = 1024 * 1024 * 100
+ obj.vcpus = 2
+ obj.name = "demo"
+ obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
+ obj.os_type = "linux"
+ obj.os_kernel = "/tmp/vmlinuz"
+ obj.os_initrd = "/tmp/ramdisk"
+ obj.os_root = "root=xvda"
+ obj.os_cmdline = "console=xvc0"
+
+ disk = config.LibvirtConfigGuestDisk()
+ disk.source_type = "file"
+ disk.source_path = "/tmp/img"
+ disk.target_dev = "/dev/xvda"
+ disk.target_bus = "xen"
+
+ obj.add_device(disk)
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <domain type="xen">
+ <uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
+ <name>demo</name>
+ <memory>104857600</memory>
+ <vcpu>2</vcpu>
+ <os>
+ <type>linux</type>
+ <kernel>/tmp/vmlinuz</kernel>
+ <initrd>/tmp/ramdisk</initrd>
+ <cmdline>console=xvc0</cmdline>
+ <root>root=xvda</root>
+ </os>
+ <devices>
+ <disk type="file" device="disk">
+ <source file="/tmp/img"/>
+ <target bus="xen" dev="/dev/xvda"/>
+ </disk>
+ </devices>
+ </domain>""")
+
+ def test_config_kvm(self):
+ obj = config.LibvirtConfigGuest()
+ obj.virt_type = "kvm"
+ obj.memory = 1024 * 1024 * 100
+ obj.vcpus = 2
+ obj.name = "demo"
+ obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
+ obj.os_type = "linux"
+ obj.os_boot_dev = "hd"
+
+ disk = config.LibvirtConfigGuestDisk()
+ disk.source_type = "file"
+ disk.source_path = "/tmp/img"
+ disk.target_dev = "/dev/vda"
+ disk.target_bus = "virtio"
+
+ obj.add_device(disk)
+
+ xml = obj.to_xml()
+ self.assertXmlEqual(xml, """
+ <domain type="kvm">
+ <uuid>b38a3f43-4be2-4046-897f-b67c2f5e0147</uuid>
+ <name>demo</name>
+ <memory>104857600</memory>
+ <vcpu>2</vcpu>
+ <os>
+ <type>linux</type>
+ <boot dev="hd"/>
+ </os>
+ <devices>
+ <disk type="file" device="disk">
+ <source file="/tmp/img"/>
+ <target bus="virtio" dev="/dev/vda"/>
+ </disk>
+ </devices>
+ </domain>""")
diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py
new file mode 100644
index 000000000..44790a068
--- /dev/null
+++ b/nova/virt/libvirt/config.py
@@ -0,0 +1,358 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Configuration for libvirt objects.
+
+Classes to represent the configuration of various libvirt objects
+and support conversion to/from XML
+"""
+
+from nova import log as logging
+
+from lxml import etree
+
+
+LOG = logging.getLogger(__name__)
+
+
+class LibvirtConfigObject(object):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigObject, self).__init__()
+
+ self.root_name = kwargs.get("root_name")
+ self.ns_prefix = kwargs.get('ns_prefix')
+ self.ns_uri = kwargs.get('ns_uri')
+
+ if "xml_str" in kwargs:
+ self.parse_dom(kwargs.get("xml_str"))
+
+ def _text_node(self, name, value):
+ child = etree.Element(name)
+ child.text = str(value)
+ return child
+
+ def format_dom(self):
+ if self.ns_uri is None:
+ return etree.Element(self.root_name)
+ else:
+ return etree.Element("{" + self.ns_uri + "}" + self.root_name,
+ nsmap={self.ns_prefix: self.ns_uri})
+
+ def parse_dom(xmldoc):
+ raise NotImplementedError()
+
+ def to_xml(self, pretty_print=True):
+ root = self.format_dom()
+ xml_str = etree.tostring(root, pretty_print=pretty_print)
+ LOG.debug("Generated XML %s " % (xml_str,))
+ return xml_str
+
+
+class LibvirtConfigGuestDevice(LibvirtConfigObject):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestDevice, self).__init__(**kwargs)
+
+
+class LibvirtConfigGuestDisk(LibvirtConfigGuestDevice):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestDisk, self).__init__(root_name="disk",
+ **kwargs)
+
+ self.source_type = "file"
+ self.source_device = "disk"
+ self.driver_name = None
+ self.driver_format = None
+ self.driver_cache = None
+ self.source_path = None
+ self.source_protocol = None
+ self.source_host = None
+ self.target_dev = None
+ self.target_path = None
+ self.target_bus = None
+
+ def format_dom(self):
+ dev = super(LibvirtConfigGuestDisk, self).format_dom()
+
+ dev.set("type", self.source_type)
+ dev.set("device", self.source_device)
+ if self.driver_name is not None or \
+ self.driver_format is not None or \
+ self.driver_cache is not None:
+ drv = etree.Element("driver")
+ if self.driver_name is not None:
+ drv.set("name", self.driver_name)
+ if self.driver_format is not None:
+ drv.set("type", self.driver_format)
+ if self.driver_cache is not None:
+ drv.set("cache", self.driver_cache)
+ dev.append(drv)
+
+ if self.source_type == "file":
+ dev.append(etree.Element("source", file=self.source_path))
+ elif self.source_type == "block":
+ dev.append(etree.Element("source", dev=self.source_path))
+ elif self.source_type == "mount":
+ dev.append(etree.Element("source", dir=self.source_path))
+ elif self.source_type == "network":
+ dev.append(etree.Element("source", protocol=self.source_protocol,
+ name=self.source_host))
+
+ if self.source_type == "mount":
+ dev.append(etree.Element("target", dir=self.target_path))
+ else:
+ dev.append(etree.Element("target", dev=self.target_dev,
+ bus=self.target_bus))
+
+ return dev
+
+
+class LibvirtConfigGuestFilesys(LibvirtConfigGuestDevice):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestFilesys, self).__init__(root_name="filesystem",
+ **kwargs)
+
+ self.source_type = "mount"
+ self.source_dir = None
+ self.target_dir = "/"
+
+ def format_dom(self):
+ dev = super(LibvirtConfigGuestFilesys, self).format_dom()
+
+ dev.set("type", self.source_type)
+
+ dev.append(etree.Element("source", dir=self.source_dir))
+ dev.append(etree.Element("target", dir=self.target_dir))
+
+ return dev
+
+
+class LibvirtConfigGuestInterface(LibvirtConfigGuestDevice):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestInterface, self).__init__(
+ root_name="interface",
+ **kwargs)
+
+ self.net_type = None
+ self.target_dev = None
+ self.model = None
+ self.mac_addr = None
+ self.script = None
+ self.source_dev = None
+ self.vporttype = None
+ self.vportparams = []
+ self.filtername = None
+ self.filterparams = []
+
+ def format_dom(self):
+ dev = super(LibvirtConfigGuestInterface, self).format_dom()
+
+ dev.set("type", self.net_type)
+ dev.append(etree.Element("mac", address=self.mac_addr))
+ if self.model:
+ dev.append(etree.Element("model", type=self.model))
+ if self.net_type == "ethernet":
+ if self.script is not None:
+ dev.append(etree.Element("script", path=self.script))
+ dev.append(etree.Element("target", dev=self.target_dev))
+ elif self.net_type == "direct":
+ dev.append(etree.Element("source", dev=self.source_dev,
+ mode="private"))
+ else:
+ dev.append(etree.Element("source", bridge=self.source_dev))
+
+ if self.vporttype is not None:
+ vport = etree.Element("virtualport", type=self.vporttype)
+ for p in self.vportparams:
+ param = etree.Element("parameters")
+ param.set(p['key'], p['value'])
+ vport.append(param)
+ dev.append(vport)
+
+ if self.filtername is not None:
+ filter = etree.Element("filterref", filter=self.filtername)
+ for p in self.filterparams:
+ filter.append(etree.Element("parameter",
+ name=p['key'],
+ value=p['value']))
+ dev.append(filter)
+
+ return dev
+
+ def add_filter_param(self, key, value):
+ self.filterparams.append({'key': key, 'value': value})
+
+ def add_vport_param(self, key, value):
+ self.vportparams.append({'key': key, 'value': value})
+
+
+class LibvirtConfigGuestInput(LibvirtConfigGuestDevice):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestInput, self).__init__(root_name="input",
+ **kwargs)
+
+ self.type = "tablet"
+ self.bus = "usb"
+
+ def format_dom(self):
+ dev = super(LibvirtConfigGuestInput, self).format_dom()
+
+ dev.set("type", self.type)
+ dev.set("bus", self.bus)
+
+ return dev
+
+
+class LibvirtConfigGuestGraphics(LibvirtConfigGuestDevice):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestGraphics, self).__init__(root_name="graphics",
+ **kwargs)
+
+ self.type = "vnc"
+ self.autoport = True
+ self.keymap = None
+ self.listen = None
+
+ def format_dom(self):
+ dev = super(LibvirtConfigGuestGraphics, self).format_dom()
+
+ dev.set("type", self.type)
+ if self.autoport:
+ dev.set("autoport", "yes")
+ else:
+ dev.set("autoport", "no")
+ if self.keymap:
+ dev.set("keymap", self.keymap)
+ if self.listen:
+ dev.set("listen", self.listen)
+
+ return dev
+
+
+class LibvirtConfigGuestChar(LibvirtConfigGuestDevice):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestChar, self).__init__(**kwargs)
+
+ self.type = "pty"
+ self.source_path = None
+ self.target_port = None
+
+ def format_dom(self):
+ dev = super(LibvirtConfigGuestChar, self).format_dom()
+
+ dev.set("type", self.type)
+ if self.type == "file":
+ dev.append(etree.Element("source", path=self.source_path))
+ if self.target_port is not None:
+ dev.append(etree.Element("target", port=str(self.target_port)))
+
+ return dev
+
+
+class LibvirtConfigGuestSerial(LibvirtConfigGuestChar):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestSerial, self).__init__(root_name="serial",
+ **kwargs)
+
+
+class LibvirtConfigGuestConsole(LibvirtConfigGuestChar):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuestConsole, self).__init__(root_name="console",
+ **kwargs)
+
+
+class LibvirtConfigGuest(LibvirtConfigObject):
+
+ def __init__(self, **kwargs):
+ super(LibvirtConfigGuest, self).__init__(root_name="domain",
+ **kwargs)
+
+ self.virt_type = None
+ self.uuid = None
+ self.name = None
+ self.memory = 1024 * 1024 * 500
+ self.vcpus = 1
+ self.acpi = False
+ self.os_type = None
+ self.os_kernel = None
+ self.os_initrd = None
+ self.os_cmdline = None
+ self.os_root = None
+ self.os_init_path = None
+ self.os_boot_dev = None
+ self.devices = []
+
+ def _format_basic_props(self, root):
+ root.append(self._text_node("uuid", self.uuid))
+ root.append(self._text_node("name", self.name))
+ root.append(self._text_node("memory", self.memory))
+ root.append(self._text_node("vcpu", self.vcpus))
+
+ def _format_os(self, root):
+ os = etree.Element("os")
+ os.append(self._text_node("type", self.os_type))
+ if self.os_kernel is not None:
+ os.append(self._text_node("kernel", self.os_kernel))
+ if self.os_initrd is not None:
+ os.append(self._text_node("initrd", self.os_initrd))
+ if self.os_cmdline is not None:
+ os.append(self._text_node("cmdline", self.os_cmdline))
+ if self.os_root is not None:
+ os.append(self._text_node("root", self.os_root))
+ if self.os_init_path is not None:
+ os.append(self._text_node("init", self.os_init_path))
+ if self.os_boot_dev is not None:
+ os.append(etree.Element("boot", dev=self.os_boot_dev))
+ root.append(os)
+
+ def _format_features(self, root):
+ if self.acpi:
+ features = etree.Element("features")
+ features.append(etree.Element("acpi"))
+ root.append(features)
+
+ def _format_devices(self, root):
+ if len(self.devices) == 0:
+ return
+ devices = etree.Element("devices")
+ for dev in self.devices:
+ devices.append(dev.format_dom())
+ root.append(devices)
+
+ def format_dom(self):
+ root = super(LibvirtConfigGuest, self).format_dom()
+
+ root.set("type", self.virt_type)
+
+ self._format_basic_props(root)
+ self._format_os(root)
+ self._format_features(root)
+ self._format_devices(root)
+
+ return root
+
+ def add_device(self, dev):
+ self.devices.append(dev)