>From cd821fe259734767619ccb4ca3001df0667c3aed Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso@redhat.com>
Date: Thu, 21 Apr 2011 13:13:49 -0400
Subject: [PATCH] virt-xml initial commit

---
 tests/pylint-virtinst.sh |    2 +-
 todo.txt                 |   12 +++
 virt-xml                 |  200 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 1 deletions(-)
 create mode 100644 todo.txt
 create mode 100755 virt-xml

diff --git a/tests/pylint-virtinst.sh b/tests/pylint-virtinst.sh
index 7c2a932..98c42fa 100755
--- a/tests/pylint-virtinst.sh
+++ b/tests/pylint-virtinst.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-FILES="setup.py tests/ virt-install virt-image virt-clone virt-convert virtinst/ virtconv virtconv/parsers/*.py"
+FILES="setup.py tests/ virt-install virt-image virt-clone virt-convert virt-xml virtinst/ virtconv virtconv/parsers/*.py"
 
 # Don't print pylint config warning
 NO_PYL_CONFIG=".*No config file found.*"
diff --git a/todo.txt b/todo.txt
new file mode 100644
index 0000000..9705a43
--- /dev/null
+++ b/todo.txt
@@ -0,0 +1,12 @@
+
+virt-xml:
+    change commands:
+        add device
+        remove device
+        edit device
+    targets:
+        --conn URI --guest GUESTNAME
+        --conn URI --guestfile file.xml
+    other opts:
+        --diff (just print diff)
+        --print-xml (just print new XML)
diff --git a/virt-xml b/virt-xml
new file mode 100755
index 0000000..9369991
--- /dev/null
+++ b/virt-xml
@@ -0,0 +1,200 @@
+#!/usr/bin/python -tt
+#
+# Copyright 2011 Red Hat, Inc.
+# Cole Robinson <crobinso@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+import sys
+import logging
+import optparse
+
+import libvirt
+import virtinst
+import virtinst.CapabilitiesParser
+import virtinst.cli as cli
+import virtinst.support as support
+from virtinst.VirtualCharDevice import VirtualCharDevice
+from virtinst.VirtualDevice import VirtualDevice
+from virtinst.cli import fail, print_stdout, print_stderr
+import difflib
+
+cli.setupGettext()
+
+def diff(orig, new):
+    """
+    Return a unified diff string between the passed strings
+    """
+    return "".join(difflib.unified_diff(orig.splitlines(1),
+                                        new.splitlines(1),
+                                        fromfile="Original XML",
+                                        tofile="New XML"))
+
+#########################
+# XML <device> altering #
+#########################
+
+def change_devices(guest, options):
+    devmap = {
+        VirtualDevice.VIRTUAL_DEV_DISK : options.diskopts,
+        VirtualDevice.VIRTUAL_DEV_WATCHDOG : options.watchdog,
+    }
+
+    if not any(devmap.values()):
+        return
+
+    if sum(map(int, map(bool, devmap.values()))) > 1:
+        fail(_("Only one device can be changed at a time"))
+
+    if options.device is None:
+        fail(_("A --device must be specified if altering an existing device"))
+    if options.device < 1:
+        fail(_("--device must be greater than 1"))
+
+    dev = None
+    try:
+        for devtype, devstr in devmap.items():
+            if devstr:
+                dev = guest.get_devices(devtype)[options.device - 1]
+                break
+    except Exception, e:
+        cli.log_exception()
+        fail(_("Didn't find requested device: %s" % e))
+
+    if options.diskopts:
+        cli.parse_disk(guest, options.diskopts, dev)
+    elif options.watchdog:
+        cli.parse_watchdog(guest, options.watchdog, dev)
+
+
+##################
+# main() helpers #
+##################
+
+def get_xml_flags(vm):
+    flags = 0
+    if support.check_domain_support(vm, support.SUPPORT_DOMAIN_XML_INACTIVE):
+        flags |= libvirt.VIR_DOMAIN_XML_INACTIVE
+    else:
+        logging.debug("Domain XML inactive flag not supported.")
+
+    if support.check_domain_support(vm, support.SUPPORT_DOMAIN_XML_SECURE):
+        flags |= libvirt.VIR_DOMAIN_XML_SECURE
+    else:
+        logging.debug("Domain XML secure flag not supported.")
+
+    return flags
+
+def build_guest(conn, guestname):
+    try:
+        vm = conn.lookupByName(guestname)
+    except Exception, e:
+        fail(_("Error fetching domain '%s': %s") % (guestname, e))
+
+    try:
+        flags = get_xml_flags(vm)
+    except Exception, e:
+        cli.log_exception()
+        fail(_("Error determining XML flags for '%s': %s") % (guestname, e))
+
+    try:
+        xml = vm.XMLDesc(flags)
+    except Exception, e:
+        fail(_("Error fetching XML for '%s': %s") % (guestname, e))
+
+    logging.debug("Original XML:\n%s" % xml)
+
+    try:
+        return virtinst.Guest(connection=conn, parsexml=xml)
+    except Exception, e:
+        cli.log_exception()
+        fail(_("Error parsing '%s' XML: %s") % (guestname, e))
+
+def parse_args():
+    usage = "%prog "
+    parser = cli.setupParser(usage)
+    cli.add_connect_option(parser)
+
+    parser.add_option("-g", "--guest", dest="guest",
+                      help=_("Name of guest to alter"))
+
+
+    gstg = optparse.OptionGroup(parser, _("Guest Configuration"))
+    gstg.add_option("", "--boot", dest="bootopts",
+                    help=_("Configure boot order, menu, permanent kernel "
+                           "boot, etc."))
+    parser.add_option_group(gstg)
+
+    devg = optparse.OptionGroup(parser, _("Device Configuration"))
+    devg.add_option("", "--device", type="int", dest="device",
+                    help=_("Device index"))
+
+    devg.add_option("", "--disk", dest="diskopts",
+        help=_("Specify disk device with various options. Ex.\n"
+               "--disk path=/my/existing/disk\n"
+               "--disk path=/my/new/disk,size=5 (in gigabytes)\n"
+               "--disk vol=poolname:volname,device=cdrom,bus=scsi,..."))
+
+    devg.add_option("", "--watchdog", dest="watchdog",
+                    help=_("Configure a watchdog device"))
+    parser.add_option_group(devg)
+
+    misc = optparse.OptionGroup(parser, _("Miscellaneous Options"))
+    misc.add_option("-d", "--debug", action="store_true", dest="debug",
+                    help=_("Print debugging information"))
+    parser.add_option_group(misc)
+
+    (options, cliargs) = parser.parse_args()
+    return options, cliargs
+
+def main():
+    cli.earlyLogging()
+    options, cliargs = parse_args()
+    cli.setupLogging("virt-xml", options.debug)
+
+    if cliargs:
+        fail(_("Unknown argument '%s'") % cliargs[0])
+
+    if not options.guest:
+        fail(_("--guest must be specified"))
+
+    conn = cli.getConnection(options.connect)
+    guest = build_guest(conn, options.guest)
+    origxml = guest.get_xml_config()
+
+    change_devices(guest, options)
+    cli.parse_boot(guest, options.bootopts)
+
+    newxml = guest.get_xml_config()
+    diffstr = diff(origxml, newxml)
+
+    if diffstr:
+        print_stdout(_("Requested changes:") + "\n" + diffstr)
+    else:
+        print_stdout(_("No configuration changes were generated"))
+
+    return 0
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except SystemExit, sys_e:
+        sys.exit(sys_e.code)
+    except KeyboardInterrupt:
+        cli.log_exception()
+        print_stderr(_("Installation aborted at user request"))
+    except Exception, main_e:
+        fail(main_e)
-- 
1.7.4

