summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCole Robinson <crobinso@redhat.com>2014-01-19 10:37:14 -0500
committerCole Robinson <crobinso@redhat.com>2014-01-25 17:20:29 -0500
commit748ff1c4cc249be6c3de30429ec0092a7832af33 (patch)
treee871a045cddb5c14a5b77e1df09a78335a912dab
parentffa9bb77b3a97bf03586514f6ebc5214401a15cf (diff)
downloadvirt-manager-748ff1c4cc249be6c3de30429ec0092a7832af33.tar.gz
virt-xml: Initial commit, basic set of tests
-rw-r--r--.gitignore1
-rw-r--r--man/virt-xml.pod77
-rwxr-xr-xsetup.py13
-rw-r--r--tests/__init__.py1
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-all.xml30
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-neg-num.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-pos-num.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-select-disk-target.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-select-network-mac.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-select-sound-model.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-boot.xml17
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-channel.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-clock.xml19
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-console.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-controller.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-cpu.xml24
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-disk.xml16
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-features.xml17
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-filesystem.xml18
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-graphics.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-host-device.xml17
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-memballoon.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-network.xml19
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-numatune.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-parallel.xml15
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-redirdev.xml15
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-rng.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-security.xml12
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-serial.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-smartcard.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-soundhw.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-tpm.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-vcpus.xml21
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-video.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-edit-simple-watchdog.xml13
-rw-r--r--tests/cli-test-xml/compare/virtxml-print-xml.xml17
-rw-r--r--tests/clitest.py93
-rw-r--r--tests/testdriver.xml31
-rw-r--r--virt-manager.spec.in4
-rwxr-xr-xvirt-xml283
-rw-r--r--virtinst/cli.py118
41 files changed, 1064 insertions, 48 deletions
diff --git a/.gitignore b/.gitignore
index 4171678c..3ee600eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@ po/virt-manager.pot
/man/virt-image.1
/man/virt-convert.1
/man/virt-image.5
+/man/virt-xml.1
/virt-manager.spec
/virtcli/cli.cfg
diff --git a/man/virt-xml.pod b/man/virt-xml.pod
new file mode 100644
index 00000000..720995fd
--- /dev/null
+++ b/man/virt-xml.pod
@@ -0,0 +1,77 @@
+=pod
+
+=head1 NAME
+
+virt-xml - XXX
+
+=head1 SYNOPSIS
+
+B<virt-xml> XXX
+
+=head1 DESCRIPTION
+
+B<virt-xml> XXX
+
+=head1 OPTIONS
+
+=over 4
+
+=item -h, --help
+
+Show the help message and exit
+
+=back
+
+=head2 BAR SECTION
+
+=over 2
+
+=item FOO
+
+FOO
+
+=item BAR
+
+BAR
+
+=back
+
+=head2 Miscellaneous Options
+
+=over 2
+
+=item -q, --quiet
+
+Avoid verbose output.
+
+=item -d, --debug
+
+Print debugging information
+
+=item --dry-run
+
+Proceed through the conversion process, but don't convert disks or actually
+write any converted files.
+
+=back
+
+=head1 EXAMPLES
+
+XXX
+
+=head1 BUGS
+
+Please see http://virt-manager.org/page/BugReporting
+
+=head1 COPYRIGHT
+
+Copyright (C) Red Hat, Inc, and various contributors.
+This is free software. You may redistribute copies of it under the terms
+of the GNU General Public License C<http://www.gnu.org/licenses/gpl.html>.
+There is NO WARRANTY, to the extent permitted by law.
+
+=head1 SEE ALSO
+
+L<virt-install(1)>, the project website C<http://virt-manager.org>
+
+=cut
diff --git a/setup.py b/setup.py
index 6103f938..b774f898 100755
--- a/setup.py
+++ b/setup.py
@@ -32,7 +32,7 @@ def _generate_potfiles_in():
return ret
scripts = ["virt-manager", "virt-install",
- "virt-clone", "virt-image", "virt-convert"]
+ "virt-clone", "virt-image", "virt-convert", "virt-xml"]
potfiles = "\n".join(scripts) + "\n\n"
potfiles += "\n".join(find("virtManager", "*.py")) + "\n\n"
@@ -145,7 +145,7 @@ class my_build(build):
def _make_bin_wrappers(self):
cmds = ["virt-manager", "virt-install", "virt-clone",
- "virt-image", "virt-convert"]
+ "virt-image", "virt-convert", "virt-xml"]
if not os.path.exists("build"):
os.mkdir("build")
@@ -559,7 +559,7 @@ class CheckPylint(Command):
def run(self):
files = ["setup.py", "virt-install", "virt-clone", "virt-image",
- "virt-convert", "virt-manager",
+ "virt-convert", "virt-xml", "virt-manager",
"virtcli", "virtinst", "virtconv", "virtManager",
"tests"]
@@ -590,7 +590,8 @@ setup(
"build/virt-clone",
"build/virt-install",
"build/virt-image",
- "build/virt-convert"]),
+ "build/virt-convert",
+ "build/virt-xml"]),
data_files=[
("share/virt-manager/", [
@@ -599,6 +600,7 @@ setup(
"virt-clone",
"virt-image",
"virt-convert",
+ "virt-xml",
]),
("share/glib-2.0/schemas",
["data/org.virt-manager.virt-manager.gschema.xml"]),
@@ -609,7 +611,8 @@ setup(
"man/virt-install.1",
"man/virt-clone.1",
"man/virt-image.1",
- "man/virt-convert.1"
+ "man/virt-convert.1",
+ "man/virt-xml.1"
]),
("share/man/man5", ["man/virt-image.5"]),
diff --git a/tests/__init__.py b/tests/__init__.py
index 4ab1002c..237cbb83 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -70,6 +70,7 @@ virtinstall = _import("virtinstall", "virt-install")
virtimage = _import("virtimage", "virt-image")
virtclone = _import("virtclone", "virt-clone")
virtconvert = _import("virtconvert", "virt-convert")
+virtxml = _import("virtxml", "virt-xml")
# Variable used to store a local iso or dir path to check for a distro
# Specified via 'python setup.py test_urls --path"
diff --git a/tests/cli-test-xml/compare/virtxml-edit-all.xml b/tests/cli-test-xml/compare/virtxml-edit-all.xml
new file mode 100644
index 00000000..f239b0fd
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-all.xml
@@ -0,0 +1,30 @@
+--- Original XML
++++ Altered XML
+@@ -265,21 +265,25 @@
+ <vendor id="0x04b3"/>
+ <product id="0x4485"/>
+ </source>
++ <driver name="vfio"/>
+ </hostdev>
+ <hostdev mode="subsystem" type="usb" managed="yes">
+ <source>
+ <address bus="3" device="2"/>
+ </source>
++ <driver name="vfio"/>
+ </hostdev>
+ <hostdev mode="subsystem" type="pci" managed="yes">
+ <source>
+ <address domain="0x0000" bus="0x00" slot="0x19" function="0x0"/>
+ </source>
++ <driver name="vfio"/>
+ </hostdev>
+ <hostdev mode="subsystem" type="pci" managed="yes">
+ <source>
+ <address domain="0x0003" bus="0x00" slot="0x19" function="0x0"/>
+ </source>
++ <driver name="vfio"/>
+ </hostdev>
+ <redirdev bus="usb" type="tcp">
+ <source mode="connect" host="localhost" service="4000"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-neg-num.xml b/tests/cli-test-xml/compare/virtxml-edit-neg-num.xml
new file mode 100644
index 00000000..aea38550
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-neg-num.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -258,7 +258,7 @@
+ <model type="vmvga" vram="9216" heads="1"/>
+ </video>
+ <video>
+- <model type="cirrus" vram="10240" heads="3"/>
++ <model type="qxl" vram="10240" heads="3"/>
+ </video>
+ <hostdev mode="subsystem" type="usb" managed="yes">
+ <source>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-pos-num.xml b/tests/cli-test-xml/compare/virtxml-edit-pos-num.xml
new file mode 100644
index 00000000..10a64999
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-pos-num.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -253,7 +253,7 @@
+ </graphics>
+ <sound model="sb16"/>
+ <sound model="es1370"/>
+- <sound model="ich6"/>
++ <sound model="pcspk"/>
+ <video>
+ <model type="vmvga" vram="9216" heads="1"/>
+ </video>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-disk-target.xml b/tests/cli-test-xml/compare/virtxml-edit-select-disk-target.xml
new file mode 100644
index 00000000..27b4b341
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-select-disk-target.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -65,7 +65,7 @@
+ <address type="drive" controller="0" bus="0" target="0" unit="1"/>
+ </disk>
+ <disk type="file" device="disk">
+- <source file="/tmp/foobar"/>
++ <source file="/dev/null"/>
+ <target dev="hda" bus="ide"/>
+ <iotune>
+ <read_bytes_sec>5242880</read_bytes_sec>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-network-mac.xml b/tests/cli-test-xml/compare/virtxml-edit-select-network-mac.xml
new file mode 100644
index 00000000..2d1fe324
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-select-network-mac.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -159,7 +159,7 @@
+ <interface type="ethernet">
+ <mac address="00:11:7f:33:44:55"/>
+ <script path="/etc/qemu-ifup"/>
+- <target dev="nic02"/>
++ <target dev="nic55"/>
+ </interface>
+ <interface type="direct">
+ <mac address="f0:11:22:33:44:5f"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-select-sound-model.xml b/tests/cli-test-xml/compare/virtxml-edit-select-sound-model.xml
new file mode 100644
index 00000000..10a64999
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-select-sound-model.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -253,7 +253,7 @@
+ </graphics>
+ <sound model="sb16"/>
+ <sound model="es1370"/>
+- <sound model="ich6"/>
++ <sound model="pcspk"/>
+ <video>
+ <model type="vmvga" vram="9216" heads="1"/>
+ </video>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-boot.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-boot.xml
new file mode 100644
index 00000000..76858bae
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-boot.xml
@@ -0,0 +1,17 @@
+--- Original XML
++++ Altered XML
+@@ -15,8 +15,10 @@
+ </numatune>
+ <os>
+ <type arch="i686">hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
+- <boot dev="hd"/>
++ <loader>foo.bar</loader>
++ <boot dev="network"/>
++ <bios useserial="yes"/>
++ <init>/bin/bash</init>
+ </os>
+ <features>
+ <acpi/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-channel.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-channel.xml
new file mode 100644
index 00000000..59738b52
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-channel.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -214,7 +214,7 @@
+ <console type="pty">
+ <target type="uml" port="1"/>
+ </console>
+- <channel type="pipe">
++ <channel type="null">
+ <source path="/tmp/guestfwd"/>
+ <target type="guestfwd" address="10.0.2.1" port="4600"/>
+ </channel>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-clock.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-clock.xml
new file mode 100644
index 00000000..21a00dda
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-clock.xml
@@ -0,0 +1,19 @@
+--- Original XML
++++ Altered XML
+@@ -44,10 +44,11 @@
+ <feature policy="require" name="xtpr"/>
+ <feature policy="require" name="acpi"/>
+ </cpu>
+- <clock offset="utc">
+- <timer name="rtc" tickpolicy="catchup"/>
++ <clock offset="localtime">
++ <timer name="rtc" tickpolicy="merge"/>
+ <timer name="pit" tickpolicy="delay"/>
+- <timer name="hpet" present="no"/>
++ <timer name="hpet" present="yes"/>
++ <timer name="kvmclock" present="no"/>
+ </clock>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-console.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-console.xml
new file mode 100644
index 00000000..a496d452
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-console.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -209,7 +209,7 @@
+ <target port="2"/>
+ </parallel>
+ <console type="pty">
+- <target type="virtio" port="0"/>
++ <target type="serial" port="0"/>
+ </console>
+ <console type="pty">
+ <target type="uml" port="1"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-controller.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-controller.xml
new file mode 100644
index 00000000..b59e93da
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-controller.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -98,7 +98,7 @@
+ <source file="/tmp/foobar4"/>
+ <target dev="xvdc" bus="xen"/>
+ </disk>
+- <controller type="scsi" index="0" model="virtio-scsi"/>
++ <controller type="scsi" index="2" model="lsilogic"/>
+ <controller type="usb" index="0"/>
+ <controller type="fdc" index="0"/>
+ <controller type="ide" index="0"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-cpu.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-cpu.xml
new file mode 100644
index 00000000..532ce286
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-cpu.xml
@@ -0,0 +1,24 @@
+--- Original XML
++++ Altered XML
+@@ -28,9 +28,9 @@
+ </hyperv>
+ </features>
+ <cpu mode="custom" match="exact">
+- <model fallback="allow">core2duo</model>
++ <model fallback="allow">pentium2</model>
+ <vendor>Intel</vendor>
+- <feature policy="require" name="pbe"/>
++ <feature policy="forbid" name="pbe"/>
+ <feature policy="require" name="tm2"/>
+ <feature policy="require" name="est"/>
+ <feature policy="require" name="ss"/>
+@@ -43,6 +43,7 @@
+ <feature policy="require" name="ds_cpl"/>
+ <feature policy="require" name="xtpr"/>
+ <feature policy="require" name="acpi"/>
++ <feature name="x2apic" policy="force"/>
+ </cpu>
+ <clock offset="utc">
+ <timer name="rtc" tickpolicy="catchup"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-disk.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-disk.xml
new file mode 100644
index 00000000..fad2b8b8
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-disk.xml
@@ -0,0 +1,16 @@
+--- Original XML
++++ Altered XML
+@@ -55,9 +55,10 @@
+ <devices>
+ <emulator>/usr/lib/xen/bin/qemu-dm</emulator>
+ <disk type="block" device="floppy">
+- <source dev="/dev/null"/>
++ <source dev="/dev/zero" startupPolicy="optional"/>
+ <target dev="fda" bus="fdc"/>
+ <address type="drive" controller="0" bus="0" target="0" unit="0"/>
++ <readonly/>
+ </disk>
+ <disk type="dir" device="floppy">
+ <source dir="/tmp"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-features.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-features.xml
new file mode 100644
index 00000000..36fb2e0e
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-features.xml
@@ -0,0 +1,17 @@
+--- Original XML
++++ Altered XML
+@@ -19,10 +19,9 @@
+ <boot dev="hd"/>
+ </os>
+ <features>
+- <acpi/>
+- <apic eoi="off"/>
++ <apic eoi="on"/>
+ <hyperv>
+- <relaxed state="on"/>
++ <relaxed state="off"/>
+ <vapic state="on"/>
+ <spinlocks state="on" retries="12287"/>
+ </hyperv>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-filesystem.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-filesystem.xml
new file mode 100644
index 00000000..720cb540
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-filesystem.xml
@@ -0,0 +1,18 @@
+--- Original XML
++++ Altered XML
+@@ -105,10 +105,10 @@
+ <controller type="virtio-serial" index="1"/>
+ <controller type="virtio-serial" index="0"/>
+ <controller type="ccid" index="0"/>
+- <filesystem type="mount" accessmode="passthrough">
++ <filesystem type="mount" accessmode="mapped">
+ <driver type="handle"/>
+- <source dir="/foo/bar"/>
+- <target dir="/bar/baz"/>
++ <source dir="/1/2/3"/>
++ <target dir="/4/5/6"/>
+ </filesystem>
+ <filesystem type="template" accessmode="passthrough">
+ <source name="template_fedora"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-graphics.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-graphics.xml
new file mode 100644
index 00000000..139f7c9b
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-graphics.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -238,7 +238,7 @@
+ </backend>
+ </tpm>
+ <input type="mouse" bus="ps2"/>
+- <graphics type="sdl" display=":3.4" xauth="/testdir/.Xauthority" fullscreen="yes"/>
++ <graphics type="sdl" display=":3.4" xauth="/testdir/.Xauthority" fullscreen="yes" tlsPort="5902" keymap="ja"/>
+ <graphics type="vnc" port="-1" autoport="yes"/>
+ <graphics type="vnc" port="-1" autoport="yes" listen="1.2.3.4" keymap="fi">
+ <listen type="address" address="1.2.3.4"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-host-device.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-host-device.xml
new file mode 100644
index 00000000..eef05b17
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-host-device.xml
@@ -0,0 +1,17 @@
+--- Original XML
++++ Altered XML
+@@ -262,9 +262,10 @@
+ </video>
+ <hostdev mode="subsystem" type="usb" managed="yes">
+ <source>
+- <vendor id="0x04b3"/>
+- <product id="0x4485"/>
++ <vendor id="0x0781"/>
++ <product id="0x5151"/>
+ </source>
++ <driver name="vfio"/>
+ </hostdev>
+ <hostdev mode="subsystem" type="usb" managed="yes">
+ <source>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-memballoon.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-memballoon.xml
new file mode 100644
index 00000000..e38ec27c
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-memballoon.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -293,7 +293,7 @@
+ <usbdev allow="no"/>
+ </redirfilter>
+ <watchdog model="ib700" action="poweroff"/>
+- <memballoon model="virtio"/>
++ <memballoon model="none"/>
+ <rng model="virtio">
+ <rate bytes="1234" period="2000"/>
+ <backend model="egd" type="tcp">
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-network.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-network.xml
new file mode 100644
index 00000000..288f9061
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-network.xml
@@ -0,0 +1,19 @@
+--- Original XML
++++ Altered XML
+@@ -124,11 +124,10 @@
+ <source dir="/foo/bar"/>
+ <target dir="/bar/baz"/>
+ </filesystem>
+- <interface type="network">
+- <mac address="22:22:33:54:32:10"/>
+- <source network="default"/>
++ <interface type="bridge">
++ <source bridge="br0"/>
+ <target dev="testnet0"/>
+- <model type="e1000"/>
++ <model type="virtio"/>
+ </interface>
+ <interface type="network">
+ <mac address="22:11:11:11:11:11"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-numatune.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-numatune.xml
new file mode 100644
index 00000000..3ee20e84
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-numatune.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -11,7 +11,7 @@
+ </memoryBacking>
+ <vcpu placement="static" cpuset="1-2,5-9,11,13-14">9</vcpu>
+ <numatune>
+- <memory mode="interleave" placement="auto"/>
++ <memory mode="strict" placement="auto" nodeset="1-5,7"/>
+ </numatune>
+ <os>
+ <type arch="i686">hvm</type>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-parallel.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-parallel.xml
new file mode 100644
index 00000000..2cde1c54
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-parallel.xml
@@ -0,0 +1,15 @@
+--- Original XML
++++ Altered XML
+@@ -195,8 +195,8 @@
+ <protocol type="telnet"/>
+ <target port="1"/>
+ </serial>
+- <parallel type="file">
+- <source path="/tmp/foo.log"/>
++ <parallel type="unix">
++ <source path="/some/other/log"/>
+ <target port="0"/>
+ </parallel>
+ <parallel type="unix">
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-redirdev.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-redirdev.xml
new file mode 100644
index 00000000..855e4c83
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-redirdev.xml
@@ -0,0 +1,15 @@
+--- Original XML
++++ Altered XML
+@@ -281,8 +281,8 @@
+ <address domain="0x0003" bus="0x00" slot="0x19" function="0x0"/>
+ </source>
+ </hostdev>
+- <redirdev bus="usb" type="tcp">
+- <source mode="connect" host="localhost" service="4000"/>
++ <redirdev bus="usb" type="spicevmc">
++ <source mode="connect" host="example.com" service="12345"/>
+ <protocol type="raw"/>
+ </redirdev>
+ <redirdev bus="usb" type="spicevmc">
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-rng.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-rng.xml
new file mode 100644
index 00000000..396f7699
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-rng.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -295,7 +295,7 @@
+ <watchdog model="ib700" action="poweroff"/>
+ <memballoon model="virtio"/>
+ <rng model="virtio">
+- <rate bytes="1234" period="2000"/>
++ <rate bytes="3333" period="4444"/>
+ <backend model="egd" type="tcp">
+ <source mode="connect" host="1.2.3.4" service="1234"/>
+ <protocol type="raw"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-security.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-security.xml
new file mode 100644
index 00000000..bfb10aae
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-security.xml
@@ -0,0 +1,12 @@
+--- Original XML
++++ Altered XML
+@@ -302,4 +302,7 @@
+ </backend>
+ </rng>
+ </devices>
++ <seclabel relabel="yes">
++ <label>foo,bar,baz</label>
++ </seclabel>
+ </domain>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-serial.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-serial.xml
new file mode 100644
index 00000000..71884748
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-serial.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -187,7 +187,7 @@
+ <protocol type="raw"/>
+ <address type="ccid" controller="0" slot="3"/>
+ </smartcard>
+- <serial type="null">
++ <serial type="pty">
+ <target port="0"/>
+ </serial>
+ <serial type="tcp">
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-smartcard.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-smartcard.xml
new file mode 100644
index 00000000..5d1baa4b
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-smartcard.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -170,7 +170,7 @@
+ <target dev="testnet6"/>
+ <address type="pci" domain="0x0000" bus="0x00" slot="0x07" function="0x0"/>
+ </interface>
+- <smartcard mode="host">
++ <smartcard mode="host" type="spicevmc">
+ <address type="ccid" controller="0" slot="0"/>
+ </smartcard>
+ <smartcard mode="host-certificates">
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-soundhw.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-soundhw.xml
new file mode 100644
index 00000000..3318f8eb
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-soundhw.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -251,7 +251,7 @@
+ <channel name="inputs" mode="secure"/>
+ <channel name="record" mode="insecure"/>
+ </graphics>
+- <sound model="sb16"/>
++ <sound model="pcspk"/>
+ <sound model="es1370"/>
+ <sound model="ich6"/>
+ <video>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-tpm.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-tpm.xml
new file mode 100644
index 00000000..b3ba4264
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-tpm.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -234,7 +234,7 @@
+ <input type="tablet" bus="usb"/>
+ <tpm model="tpm-tis">
+ <backend type="passthrough">
+- <device path="/dev/tzz"/>
++ <device path="/dev/tpm"/>
+ </backend>
+ </tpm>
+ <input type="mouse" bus="ps2"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-vcpus.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-vcpus.xml
new file mode 100644
index 00000000..45bcafea
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-vcpus.xml
@@ -0,0 +1,21 @@
+--- Original XML
++++ Altered XML
+@@ -9,7 +9,7 @@
+ <memoryBacking>
+ <hugepages/>
+ </memoryBacking>
+- <vcpu placement="static" cpuset="1-2,5-9,11,13-14">9</vcpu>
++ <vcpu placement="static" cpuset="1-2,5-9,11,13-14" current="10">20</vcpu>
+ <numatune>
+ <memory mode="interleave" placement="auto"/>
+ </numatune>
+@@ -43,6 +43,7 @@
+ <feature policy="require" name="ds_cpl"/>
+ <feature policy="require" name="xtpr"/>
+ <feature policy="require" name="acpi"/>
++ <topology sockets="4" cores="5" threads="1"/>
+ </cpu>
+ <clock offset="utc">
+ <timer name="rtc" tickpolicy="catchup"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-video.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-video.xml
new file mode 100644
index 00000000..d73bc719
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-video.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -255,7 +255,7 @@
+ <sound model="es1370"/>
+ <sound model="ich6"/>
+ <video>
+- <model type="vmvga" vram="9216" heads="1"/>
++ <model type="cirrus" vram="9216" heads="1"/>
+ </video>
+ <video>
+ <model type="cirrus" vram="10240" heads="3"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-edit-simple-watchdog.xml b/tests/cli-test-xml/compare/virtxml-edit-simple-watchdog.xml
new file mode 100644
index 00000000..736af59a
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-edit-simple-watchdog.xml
@@ -0,0 +1,13 @@
+--- Original XML
++++ Altered XML
+@@ -292,7 +292,7 @@
+ <usbdev class="0x08" vendor="0x15E1" product="0x2007" version="1.10" allow="yes"/>
+ <usbdev allow="no"/>
+ </redirfilter>
+- <watchdog model="ib700" action="poweroff"/>
++ <watchdog model="ib700" action="reset"/>
+ <memballoon model="virtio"/>
+ <rng model="virtio">
+ <rate bytes="1234" period="2000"/>
+
+Domain 'test-many-devices' defined successfully. \ No newline at end of file
diff --git a/tests/cli-test-xml/compare/virtxml-print-xml.xml b/tests/cli-test-xml/compare/virtxml-print-xml.xml
new file mode 100644
index 00000000..cd52f8d3
--- /dev/null
+++ b/tests/cli-test-xml/compare/virtxml-print-xml.xml
@@ -0,0 +1,17 @@
+<domain type="test" id="1">
+ <name>test</name>
+ <uuid>4a64cc71-19c4-2fd0-2323-3050941ea3c3</uuid>
+ <memory unit="KiB">8388608</memory>
+ <currentMemory unit="KiB">2097152</currentMemory>
+ <vcpu placement="static">7</vcpu>
+ <os>
+ <type arch="i686">hvm</type>
+ <boot dev="hd"/>
+ </os>
+ <clock offset="utc"/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ </devices>
+</domain>
diff --git a/tests/clitest.py b/tests/clitest.py
index 84712fcb..b78b3aee 100644
--- a/tests/clitest.py
+++ b/tests/clitest.py
@@ -30,9 +30,12 @@ import StringIO
import virtinst.cli
from virtinst import support
-from tests import virtinstall, virtimage, virtclone, virtconvert
+from tests import virtinstall, virtimage, virtclone, virtconvert, virtxml
from tests import utils
+# Enable this to refresh test output
+REGENERATE_OUTPUT = False
+
os.environ["VIRTCONV_TEST_NO_DISK_CONVERSION"] = "1"
os.environ["LANG"] = "en_US.UTF-8"
@@ -185,6 +188,8 @@ class Command(object):
ret = virtimage.main(conn=conn)
elif app.count("virt-convert"):
ret = virtconvert.main()
+ elif app.count("virt-xml"):
+ ret = virtxml.main()
except SystemExit, sys_e:
ret = sys_e.code
@@ -244,7 +249,7 @@ class Command(object):
if filename:
# Generate test files that don't exist yet
- if not os.path.exists(filename):
+ if REGENERATE_OUTPUT or not os.path.exists(filename):
file(filename, "w").write(output)
utils.diff_compare(output, filename)
@@ -260,23 +265,40 @@ class PromptCheck(object):
"""
Individual question/response pair for automated --prompt tests
"""
- def __init__(self, prompt, response=None):
+ def __init__(self, prompt, response=None, num_lines=1):
self.prompt = prompt
self.response = response
if self.response:
self.response = self.response % test_files
+ self.num_lines = num_lines
- def check(self, proc):
- out = proc.stdout.readline()
+ self._output = None
- if not out.count(self.prompt):
- out += "\nContent didn't contain prompt '%s'" % (self.prompt)
- return False, out
+ def check(self, proc):
+ timeout = 3
+ def _set_output():
+ self._output = ""
+ for ignore in range(self.num_lines):
+ self._output += proc.stdout.readline()
+
+ import threading
+ thread = threading.Thread(target=_set_output)
+ thread.start()
+ thread.join(timeout)
+
+ if thread.isAlive():
+ proc.terminate()
+ return False, self._output + "\nProcess hung on readline()"
+
+ if not self._output.count(self.prompt):
+ self._output += ("\nContent didn't contain prompt '%s'" %
+ (self.prompt))
+ return False, self._output
if self.response:
proc.stdin.write(self.response + "\n")
- return True, out
+ return True, self._output
class PromptTest(Command):
@@ -725,6 +747,54 @@ c.add_invalid("--hvm --boot kernel=%(TREEDIR)s/pxeboot/vmlinuz,initrd=%(TREEDIR)
+vixml = App("virt-xml")
+c = vixml.add_category("misc", "")
+c.add_valid("--help") # basic --help test
+c.add_valid("--soundhw=? --tpm=?") # basic introspection test
+c.add_invalid("--domain test --edit --hostdev driver_name=vfio") # Guest has no hostdev to edit
+c.add_invalid("--domain test --edit --cpu host-passthrough --boot hd,network") # Specified more than 1 option
+c.add_invalid("--domain test --edit") # specified no edit option
+c.add_invalid("--domain test --edit 2 --cpu host-passthrough") # specifing --edit number where it doesn't make sense
+c.add_invalid("--domain test-many-devices --edit 5 --tpm /dev/tpm") # device edit out of range
+c.add_compare("--domain test --print-xml --edit --vcpus 7", "virtxml-print-xml") # test --print-xml
+
+c = vixml.add_category("simple edit diff", "--domain test-many-devices --edit --print-diff --define")
+c.add_compare("--vcpus 10,maxvcpus=20,cores=5,sockets=4,threads=1", "virtxml-edit-simple-vcpus")
+c.add_compare("--cpu model=pentium2,+x2apic,forbid=pbe", "virtxml-edit-simple-cpu")
+c.add_compare("--numatune 1-5,7,mode=strict", "virtxml-edit-simple-numatune")
+c.add_compare("--boot loader=foo.bar,network,useserial=on,init=/bin/bash", "virtxml-edit-simple-boot")
+c.add_compare("--security label=foo,bar,baz,relabel=on", "virtxml-edit-simple-security")
+c.add_compare("--features eoi=on,hyperv_relaxed=off,acpi=", "virtxml-edit-simple-features")
+c.add_compare("--clock offset=localtime,hpet_present=yes,kvmclock_present=no,rtc_tickpolicy=merge", "virtxml-edit-simple-clock")
+c.add_compare("--disk /dev/zero,perms=ro,startup_policy=optional", "virtxml-edit-simple-disk")
+c.add_compare("--network source=br0,type=bridge,model=virtio,mac=", "virtxml-edit-simple-network")
+c.add_compare("--graphics tlsport=5902,keymap=ja", "virtxml-edit-simple-graphics")
+c.add_compare("--controller index=2,model=lsilogic", "virtxml-edit-simple-controller")
+c.add_compare("--smartcard type=spicevmc", "virtxml-edit-simple-smartcard")
+c.add_compare("--redirdev type=spicevmc,server=example.com:12345", "virtxml-edit-simple-redirdev")
+c.add_compare("--tpm path=/dev/tpm", "virtxml-edit-simple-tpm")
+c.add_compare("--rng rate_bytes=3333,rate_period=4444", "virtxml-edit-simple-rng")
+c.add_compare("--watchdog action=reset", "virtxml-edit-simple-watchdog")
+c.add_compare("--memballoon model=none", "virtxml-edit-simple-memballoon")
+c.add_compare("--serial pty", "virtxml-edit-simple-serial")
+c.add_compare("--parallel unix,path=/some/other/log", "virtxml-edit-simple-parallel")
+c.add_compare("--channel null", "virtxml-edit-simple-channel")
+c.add_compare("--console target_type=serial", "virtxml-edit-simple-console")
+c.add_compare("--filesystem /1/2/3,/4/5/6,mode=mapped", "virtxml-edit-simple-filesystem")
+c.add_compare("--video cirrus", "virtxml-edit-simple-video")
+c.add_compare("--soundhw pcspk", "virtxml-edit-simple-soundhw")
+c.add_compare("--host-device 0x0781:0x5151,driver_name=vfio", "virtxml-edit-simple-host-device")
+
+c = vixml.add_category("edit selection", "--domain test-many-devices --print-diff --define")
+c.add_invalid("--edit target=vvv --disk /dev/null") # no match found
+c.add_compare("--edit 3 --soundhw pcspk", "virtxml-edit-pos-num")
+c.add_compare("--edit -1 --video qxl", "virtxml-edit-neg-num")
+c.add_compare("--edit all --host-device driver_name=vfio", "virtxml-edit-all")
+c.add_compare("--edit ich6 --soundhw pcspk", "virtxml-edit-select-sound-model")
+c.add_compare("--edit target=hda --disk /dev/null", "virtxml-edit-select-disk-target")
+c.add_compare("--edit mac=00:11:7f:33:44:55 --network target=nic55", "virtxml-edit-select-network-mac")
+
+
vimag = App("virt-image")
c = vimag.add_category("graphics", "--name test-image --boot 0 %(IMAGE_XML)s")
c.add_valid("--sdl") # SDL
@@ -887,6 +957,10 @@ p7.add("'/root' must be a file or a device")
p7.add("use as the cloned disk", "%(MANAGEDNEW1)s")
promptlist.append(p7)
+p8 = PromptTest("virt-xml --connect %(TESTURI)s --confirm --domain test "
+ "--edit --cpu host-passthrough")
+p8.add("Define 'test' with the changed XML", "yes", num_lines=12)
+promptlist.append(p8)
#########################
@@ -949,6 +1023,7 @@ _cmdlist += vinst.cmds
_cmdlist += vclon.cmds
_cmdlist += vimag.cmds
_cmdlist += vconv.cmds
+_cmdlist += vixml.cmds
for _cmd in _cmdlist:
newidx += 1
diff --git a/tests/testdriver.xml b/tests/testdriver.xml
index 218f57e9..1e709ee1 100644
--- a/tests/testdriver.xml
+++ b/tests/testdriver.xml
@@ -71,13 +71,26 @@
yeah boii &lt; &gt; yeahfoo
</description>
<features>
- <acpi/><apic/>
+ <acpi/>
+ <apic eoi='off'/>
+ <hyperv>
+ <relaxed state='on'/>
+ <vapic state='on'/>
+ <spinlocks state='on' retries='12287'/>
+ </hyperv>
</features>
- <clock offset="utc"/>
+ <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>
<vcpu cpuset="1,2,5-9,11,13-14">9</vcpu>
+ <numatune>
+ <memory mode='interleave' placement='auto'/>
+ </numatune>
<cpu match="exact">
<model>core2duo</model>
<vendor>Intel</vendor>
@@ -148,14 +161,13 @@
</interface>
<interface type='network'>
<source network='idontexistfool'/>
+ <mac address='22:11:11:11:11:11'/>
</interface>
<interface type='network'>
<source network='dupmac'/>
<mac address='22:22:33:54:32:11'/>
</interface>
- <interface type='user'>
- <mac address='22:11:11:11:11:11'/>
- </interface>
+ <interface type='user'/>
<interface type='bridge'>
<source bridge='brempty'/>
<mac address='22:22:33:44:AA:BB'/>
@@ -166,9 +178,8 @@
<mac address='22:00:00:44:AA:BF'/>
<model type='e1000'/>
</interface>
- <controller type='usb'/>
<interface type='ethernet'>
- <mac address='00:11:7F:33:44:55'/>
+ <mac address='00:11:7f:33:44:55'/>
<script path='/etc/qemu-ifup'/>
<target dev='nic02'/>
</interface>
@@ -200,6 +211,9 @@
<channel name="record" mode="insecure"/>
</graphics>
+ <!-- controller devices -->
+ <controller type='scsi' model='virtio-scsi'/>
+ <controller type='usb'/>
<!-- sound devices -->
<sound model='sb16'/>
@@ -363,6 +377,9 @@
<panic>
<address type='isa' iobase='0x505'/>
</panic>
+
+ <!-- memballoon device -->
+ <memballoon model='virtio'/>
</devices>
</domain>
diff --git a/virt-manager.spec.in b/virt-manager.spec.in
index 45a3af81..3c06319e 100644
--- a/virt-manager.spec.in
+++ b/virt-manager.spec.in
@@ -93,6 +93,7 @@ Provides: virt-install
Provides: virt-clone
Provides: virt-image
Provides: virt-convert
+Provides: virt-xml
Obsoletes: python-virtinst
%description -n virt-install
@@ -194,6 +195,7 @@ fi
%{_mandir}/man1/virt-install.1*
%{_mandir}/man1/virt-clone.1*
%{_mandir}/man1/virt-convert.1*
+%{_mandir}/man1/virt-xml.1*
%{_mandir}/man1/virt-image.1*
%{_mandir}/man5/virt-image.5*
@@ -201,11 +203,13 @@ fi
%{_datadir}/%{name}/virt-clone
%{_datadir}/%{name}/virt-image
%{_datadir}/%{name}/virt-convert
+%{_datadir}/%{name}/virt-xml
%{_bindir}/virt-install
%{_bindir}/virt-clone
%{_bindir}/virt-image
%{_bindir}/virt-convert
+%{_bindir}/virt-xml
%changelog
diff --git a/virt-xml b/virt-xml
new file mode 100755
index 00000000..182f160e
--- /dev/null
+++ b/virt-xml
@@ -0,0 +1,283 @@
+#!/usr/bin/python -tt
+#
+# Copyright 2013 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 difflib
+import logging
+import os
+import sys
+
+import libvirt
+
+import virtinst
+from virtinst import cli
+from virtinst.cli import fail, print_stdout, print_stderr
+
+
+###################
+# Utility helpers #
+###################
+
+def prompt_yes_or_no(msg):
+ while 1:
+ printmsg = msg + " (y/n): "
+ if "VIRTINST_TEST_SUITE" in os.environ:
+ printmsg += "\n"
+ sys.stdout.write(printmsg)
+ sys.stdout.flush()
+
+ inp = sys.stdin.readline().lower().strip()
+ if inp in ["y", "yes"]:
+ return True
+ elif inp in ["n", "no"]:
+ return False
+ else:
+ print_stdout(_("Please enter 'yes' or 'no'."))
+
+
+def get_diff(origxml, newxml):
+ ret = "".join(difflib.unified_diff(origxml.splitlines(1),
+ newxml.splitlines(1),
+ fromfile="Original XML",
+ tofile="Altered XML"))
+
+ if ret:
+ logging.debug("XML diff:\n%s", ret)
+ else:
+ logging.debug("No XML diff, didn't generate any change.")
+ return ret
+
+
+def get_domain_and_guest(conn, domstr):
+ if not domstr:
+ fail("--domain must be specified")
+
+ try:
+ int(domstr)
+ isint = True
+ except ValueError:
+ isint = False
+
+ try:
+ virtinst.util.validate_uuid(domstr)
+ isuuid = True
+ except ValueError:
+ isuuid = False
+
+ try:
+ if isint:
+ domain = conn.lookupByID(int(domstr))
+ elif isuuid:
+ domain = conn.lookupByUUIDString(domstr)
+ else:
+ domain = conn.lookupByName(domstr)
+ except libvirt.libvirtError, e:
+ fail(_("Could not find domain '%s': %s") % (domstr, e))
+
+ # XXX: Require this for first pass, but it sucks for testing
+ #if domain.info()[0] != libvirt.VIR_DOMAIN_SHUTOFF:
+ # fail(_("Domain '%s' must be shutoff.") % domain.name())
+
+ # XXX: any flags to use here? INACTIVE prob, though not secure or cpu
+ xml = domain.XMLDesc(0)
+
+ # We do this to minimize the diff, removing things like ' -> "
+ xml = virtinst.Guest(conn, parsexml=xml).get_xml_config()
+ return (domain, xml, virtinst.Guest(conn, parsexml=xml))
+
+
+################
+# Change logic #
+################
+
+def _find_devices_to_edit(guest, options, parserobj):
+ devlist = guest.get_devices(parserobj.devclass.virtual_device_type)
+ idx = None
+
+ if options.edit is None:
+ idx = 1
+ elif (options.edit.isdigit() or
+ options.edit.startswith("-") and options.edit[1:].isdigit()):
+ idx = int(options.edit)
+
+ if idx is not None:
+ if idx == 0:
+ fail(_("Invalid --edit option '%s'") % options.edit)
+
+ if not devlist:
+ fail(_("No --%s devices found in the XML") %
+ parserobj.cli_arg_name)
+ if len(devlist) < abs(idx):
+ fail(_("--edit %s requested but there's only %s "
+ "--%s devices in the XML") %
+ (idx, len(devlist), parserobj.cli_arg_name))
+
+ if idx > 0:
+ idx -= 1
+ inst = devlist[idx]
+ elif options.edit == "all":
+ inst = devlist[:]
+ else:
+ inst = parserobj.lookup_device_from_option_string(guest, options.edit)
+ if not inst:
+ fail(_("No matching devices found for --edit %s") % options.edit)
+
+ return inst
+
+
+def change_xml(guest, options, parsermap):
+ # XXX: Make sure actions don't conflict
+ # XXX: Make sure XML options don't conflict
+ # XXX: Find a way to factor out whatever defaults there are
+ if options.edit is -1:
+ fail("--edit must be specified")
+
+ collisions = []
+ for option_variable_name, parserobj in parsermap.items():
+ if getattr(options, option_variable_name):
+ collisions.append(parserobj)
+
+ if len(collisions) == 0:
+ fail(_("No change specified."))
+ if len(collisions) != 1:
+ fail(_("Only one change operation may be specified "
+ "(conflicting options %s)") %
+ ["--" + c.cli_arg_name for c in collisions])
+ parserobj = collisions[0]
+
+ if parserobj.devclass:
+ inst = _find_devices_to_edit(guest, options, parserobj)
+ else:
+ inst = guest
+ if options.edit and options.edit != '1' and options.edit != 'all':
+ fail(_("'--edit %s' doesn't make sense with --%s, "
+ "just use empty '--edit'") %
+ (options.edit, parserobj.cli_arg_name))
+
+ cli.parse_option_strings(parsermap, options, guest, inst)
+
+
+#######################
+# CLI option handling #
+#######################
+
+def parse_args():
+ # XXX: man page: mention introspection if it makes sense
+ # XXX: expand usage
+ # XXX: notes about the default actions, behavior, etc
+ parser = cli.setupParser(
+ "%(prog)s [options]",
+ _("Edit libvirt XML using command line options."),
+ introspection_epilog=True)
+
+ cli.add_connect_option(parser)
+
+ actg = parser.add_argument_group(_("Action Options"))
+ actg.add_argument("--domain", help=_("Domain name, id, or uuid"))
+ actg.add_argument("--edit", nargs='?', default=-1,
+ help=_("Edit VM XML"))
+
+ g = parser.add_argument_group(_("XML options"))
+ cli.add_disk_option(g)
+ cli.add_net_option(g)
+ cli.add_gfx_option(g)
+ cli.vcpu_cli_options(g)
+ cli.add_guest_xml_options(g)
+ cli.add_boot_option(g)
+ cli.add_fs_option(g)
+ cli.add_device_options(g)
+
+ misc = parser.add_argument_group(_("Miscellaneous Options"))
+ cli.add_misc_options(misc, prompt=False, printxml=False, dryrun=False)
+ misc.add_argument("--print-diff", action="store_true",
+ help=_("Only print the requested change, in diff format"))
+ misc.add_argument("--print-xml", action="store_true",
+ help=_("Only print the requested change, in full XML format"))
+ misc.add_argument("--confirm", action="store_true",
+ help=_("Require confirmation before saving any results."))
+ misc.add_argument("--define", action="store_true",
+ help=_("Force defining the domain, only required if a --print "
+ "option was specified."))
+
+ return parser.parse_args()
+
+
+###################
+# main() handling #
+###################
+
+def main(conn=None):
+ cli.earlyLogging()
+ options = parse_args()
+
+ if options.confirm or options.print_xml or options.print_diff:
+ options.quiet = False
+ if not options.print_xml and not options.print_diff:
+ options.define = True
+ if options.confirm and not options.print_xml:
+ options.print_diff = True
+
+ cli.setupLogging("virt-xml", options.debug, options.quiet)
+
+ parsermap = cli.build_parser_map(options)
+ if cli.check_option_introspection(options, parsermap):
+ return 0
+
+ if conn is None:
+ conn = cli.getConnection(options.connect)
+
+ domain, origxml, guest = get_domain_and_guest(conn, options.domain)
+ # XXX: do we ever need the domain?
+ ignore = domain
+
+ change_xml(guest, options, parsermap)
+
+ newxml = guest.get_xml_config()
+ diff = get_diff(origxml, newxml)
+
+ if options.print_diff:
+ if diff:
+ print_stdout(diff)
+ elif options.print_xml:
+ print_stdout(newxml)
+
+ if not options.define:
+ return 0
+
+ if options.confirm:
+ # XXX: Message needs to depend on what action we will take
+ if not prompt_yes_or_no(
+ _("Define '%s' with the changed XML?" % guest.name)):
+ return 0
+
+ conn.defineXML(guest.get_xml_config())
+ print_stdout(_("Domain '%s' defined successfully." % guest.name))
+ return 0
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main())
+ except SystemExit, sys_e:
+ sys.exit(sys_e.code)
+ except KeyboardInterrupt:
+ logging.debug("", exc_info=True)
+ print_stderr(_("Aborted at user request"))
+ except Exception, main_e:
+ fail(main_e)
diff --git a/virtinst/cli.py b/virtinst/cli.py
index 6e074487..7c9b10f8 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -974,39 +974,39 @@ class _VirtCLIArgument(object):
self.ignore_default = ignore_default
- def parse(self, opts, inst, support_cb=None):
+ def parse(self, opts, inst, support_cb=None, lookup=False):
val = opts.get_opt_param(self.cliname)
if val is None:
return
+ if val == "":
+ val = None
if support_cb:
support_cb(inst, self.attrname, self.cliname)
if self.is_onoff:
val = _on_off_convert(self.cliname, val)
- if val == "default" and self.ignore_default:
+ if val == "default" and self.ignore_default and not lookup:
return
- attr = None
+ if lookup and not self.attrname:
+ raise RuntimeError(_("Don't know how to match %s property %s") %
+ (getattr(inst, "virtual_device_type", ""), self.cliname))
+
try:
- if self.setter_cb:
- attr = None
- elif callable(self.attrname):
- attr = self.attrname
- else:
- attr = eval("inst." + self.attrname)
+ if self.attrname:
+ eval("inst." + self.attrname)
except AttributeError:
raise RuntimeError("programming error: obj=%s does not have "
"member=%s" % (inst, self.attrname))
- if self.setter_cb:
+ if lookup:
+ return eval("inst." + self.attrname) == val
+ elif self.setter_cb:
self.setter_cb(opts, inst, self.cliname, val)
- elif callable(attr):
- attr(val)
else:
exec("inst." + self.attrname + " = val") # pylint: disable=W0122
-
class VirtOptionString(object):
def __init__(self, optstr, virtargs, remove_first=None):
"""
@@ -1116,7 +1116,11 @@ class VirtCLIParser(object):
A command line argument just extends this interface, implements
_init_params, and calls set_param in the order it wants the options
parsed on the command line. See existing impls examples of how to
- do all sorts of crazy stuff
+ do all sorts of crazy stuff.
+
+ set_param must be set unconditionally (ex from _init_params and not
+ from overriding _parse), so that we can show all options when the
+ user requests command line introspection like --disk=?
"""
devclass = None
@@ -1206,6 +1210,28 @@ class VirtCLIParser(object):
return ret[0]
return ret
+ def lookup_device_from_option_string(self, guest, optstr):
+ """
+ Given a passed option string, search the guests' device list
+ for all devices which match the passed options.
+ """
+ devlist = guest.get_devices(self.devclass.virtual_device_type)[:]
+ ret = []
+
+ for inst in devlist:
+ opts = VirtOptionString(optstr, self._params,
+ remove_first=self.remove_first)
+ valid = True
+ for param in self._params:
+ if param.parse(opts, inst,
+ support_cb=None, lookup=True) is False:
+ valid = False
+ break
+ if valid:
+ ret.append(inst)
+
+ return ret
+
def _parse_single_optstr(self, guest, optstr, inst):
if not optstr:
return None
@@ -1249,9 +1275,9 @@ class ParserNumatune(VirtCLIParser):
self.set_param("numatune.memory_mode", "mode")
-##################
-# --vcpu parsing #
-##################
+###################
+# --vcpus parsing #
+###################
class ParserVCPU(VirtCLIParser):
def _init_params(self):
@@ -1317,7 +1343,17 @@ class ParserCPU(VirtCLIParser):
ignore = opts
policy = cliname
for feature_name in util.listify(val):
- inst.cpu.add_feature(feature_name, policy)
+ featureobj = None
+
+ for f in inst.cpu.features:
+ if f.name == feature_name:
+ featureobj = f
+ break
+
+ if featureobj:
+ featureobj.policy = policy
+ else:
+ inst.cpu.add_feature(feature_name, policy)
self.set_param(None, "model", setter_cb=set_model_cb)
self.set_param("cpu.match", "match")
@@ -1627,7 +1663,7 @@ class ParserNetwork(VirtCLIParser):
self.set_param("source_mode", "source_mode")
self.set_param("target_dev", "target")
self.set_param("model", "model")
- self.set_param(None, "mac", setter_cb=set_mac_cb)
+ self.set_param("macaddr", "mac", setter_cb=set_mac_cb)
self.set_param("filterref", "filterref")
def _parse(self, optsobj, inst):
@@ -1701,7 +1737,11 @@ class ParserController(VirtCLIParser):
self.set_param("model", "model")
self.set_param("index", "index")
self.set_param("master_startport", "master")
- self.set_param("address.set_addrstr", "address")
+
+ def set_server_cb(opts, inst, cliname, val):
+ ignore = opts = cliname
+ inst.address.set_addrstr(val)
+ self.set_param(None, "address", setter_cb=set_server_cb)
def _parse(self, opts, inst):
if opts.fullopts == "usb2":
@@ -1739,7 +1779,12 @@ class ParserRedir(VirtCLIParser):
self.set_param("bus", "bus")
self.set_param("type", "type")
- self.set_param("parse_friendly_server", "server")
+
+ def set_server_cb(opts, inst, cliname, val):
+ ignore = opts = cliname
+ inst.parse_friendly_server(val)
+
+ self.set_param(None, "server", setter_cb=set_server_cb)
#################
@@ -1893,15 +1938,28 @@ class _ParserChar(VirtCLIParser):
"optname" : cliname})
self.support_cb = support_check
+
self.set_param("type", "char_type")
self.set_param("source_path", "path")
self.set_param("source_mode", "mode")
self.set_param("protocol", "protocol")
self.set_param("target_type", "target_type")
self.set_param("target_name", "name")
- self.set_param("set_friendly_source", "host")
- self.set_param("set_friendly_bind", "bind_host")
- self.set_param("set_friendly_target", "target_address")
+
+ def set_host_cb(opts, inst, cliname, val):
+ ignore = opts = cliname
+ inst.set_friendly_source(val)
+ self.set_param(None, "host", setter_cb=set_host_cb)
+
+ def set_bind_cb(opts, inst, cliname, val):
+ ignore = opts = cliname
+ inst.set_friendly_bind(val)
+ self.set_param(None, "bind_host", setter_cb=set_bind_cb)
+
+ def set_target_cb(opts, inst, cliname, val):
+ ignore = opts = cliname
+ inst.set_friendly_target(val)
+ self.set_param(None, "target_address", setter_cb=set_target_cb)
def _parse(self, opts, inst):
if opts.fullopts == "none" and inst.virtual_device_type == "console":
@@ -2042,17 +2100,23 @@ def build_parser_map(options, skip=None, only=None):
return parsermap
-def parse_option_strings(parsermap, options, guest, inst):
+def parse_option_strings(parsermap, options, guest, instlist):
"""
Iterate over the parsermap, and launch the associated parser
function for every value that was filled in on 'options', which
came from argparse/the command line.
"""
+ instlist = util.listify(instlist)
+ if not instlist:
+ instlist = [None]
+
for option_variable_name in dir(options):
if option_variable_name not in parsermap:
continue
- parsermap[option_variable_name].parse(
- guest, getattr(options, option_variable_name), inst)
+
+ for inst in util.listify(instlist):
+ parsermap[option_variable_name].parse(
+ guest, getattr(options, option_variable_name), inst)
def check_option_introspection(options, parsermap):