Devel
Threads by month
- ----- 2026 -----
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 25 participants
- 40185 discussions
20 Sep '16
https://bugzilla.redhat.com/show_bug.cgi?id=1365823
For virtio-blk, scsi=on has been deprecated in virtio-1,
so <disk type='block' device='lun'> no longer works with
with a virtio-blk-pci device with machine types newer than 2.7:
https://bugzilla.redhat.com/show_bug.cgi?id=1245453
http://git.qemu.org/?p=qemu.git;a=commitdiff;h=9a4c0e22
Add disable-modern=on on the QEMU command line to prolong
the suffering for a while longer.
---
The alternative would be using the QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY
capability to report an error, instead of waiting until QEMU fails with
an error, since it's the first commit when the following error should
be reachable via libvirt-generated command line:
http://git.qemu.org/?p=qemu.git;a=commitdiff;h=efb8206c
src/qemu/qemu_command.c | 12 +++++
.../qemuxml2argv-virtio-lun-legacy.args | 30 +++++++++++++
.../qemuxml2argv-virtio-lun-legacy.xml | 52 ++++++++++++++++++++++
tests/qemuxml2argvtest.c | 3 ++
4 files changed, 97 insertions(+)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.xml
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 051a0bc..03dc20e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2075,6 +2075,18 @@ qemuBuildDriveDevStr(const virDomainDef *def,
virBufferAddLit(&opt, "virtio-blk-pci");
if (disk->iothread)
virBufferAsprintf(&opt, ",iothread=iothread%u", disk->iothread);
+
+ /*
+ * SCSI command passthrough was deprecated in virtio 1.0,
+ * see https://bugzilla.redhat.com/show_bug.cgi?id=1365823
+ */
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SCSI) &&
+ disk->device == VIR_DOMAIN_DISK_DEVICE_LUN &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY)) {
+ VIR_WARN("lun type devices are deprecated for virtio-blk-pci devices, "
+ "consider using disks on a virtio-scsi controller");
+ virBufferAddLit(&opt, ",disable-modern=on");
+ }
}
qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
if (disk->event_idx &&
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.args b/tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.args
new file mode 100644
index 0000000..d1ff31c
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.args
@@ -0,0 +1,30 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name test \
+-S \
+-M pc-0.13 \
+-m 1024 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid bba65c0e-c049-934f-b6aa-4e2c0582acdf \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-test/monitor.sock,server,nowait \
+-no-acpi \
+-boot dc \
+-device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
+-usb \
+-drive file=/dev/sdfake,format=qcow2,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,disable-modern=on,scsi=on,bus=pci.0,addr=0x4,\
+drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/dev/sdfake2,format=qcow2,if=none,id=drive-virtio-disk1 \
+-device virtio-blk-pci,disable-modern=on,scsi=on,bus=pci.0,addr=0x5,\
+drive=drive-virtio-disk1,id=virtio-disk1 \
+-device virtio-net-pci,vlan=0,id=net0,mac=52:54:00:e5:48:58,bus=pci.0,addr=0x3 \
+-net user,vlan=0,name=hostnet0 \
+-serial pty \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.xml b/tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.xml
new file mode 100644
index 0000000..63dbfda
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-virtio-lun-legacy.xml
@@ -0,0 +1,52 @@
+<domain type='qemu'>
+ <name>test</name>
+ <uuid>bba65c0e-c049-934f-b6aa-4e2c0582acdf</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-0.13'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='lun' rawio='yes'>
+ <driver name='qemu' type='qcow2'/>
+ <source dev='/dev/sdfake'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='block' device='lun'>
+ <driver name='qemu' type='qcow2'/>
+ <source dev='/dev/sdfake2'/>
+ <target dev='vdb' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </controller>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='user'>
+ <mac address='52:54:00:e5:48:58'/>
+ <model type='virtio'/>
+ <driver name='vhost' event_idx='off'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index e854077..afe3073 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -931,6 +931,9 @@ mymain(void)
QEMU_CAPS_VIRTIO_BLK_SCSI);
DO_TEST("virtio-lun",
QEMU_CAPS_VIRTIO_BLK_SCSI);
+ DO_TEST("virtio-lun-legacy",
+ QEMU_CAPS_VIRTIO_BLK_SCSI,
+ QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY);
DO_TEST("disk-scsi-lun-passthrough",
QEMU_CAPS_SCSI_BLOCK,
QEMU_CAPS_SCSI_LSI, QEMU_CAPS_VIRTIO_SCSI);
--
2.7.3
3
2
[libvirt] [PATCH] virtlogd: Don't stop or restart along with libvirtd
by Andrea Bolognani 20 Sep '16
by Andrea Bolognani 20 Sep '16
20 Sep '16
Commit 839a060 tied the lifecycle of virtlogd more
closely to that of libvirtd. Unfortunately, while starting
virtlogd when libvirtd is started is definitely a good idea,
restarting virtlogd or shutting it down at any time outside
of system poweroff is not.
Revert part of that commit by removing the PartOf= lines,
meaning that only startup requests will be propagated from
libvirtd to virtlogd.
Resolves: https://bugzilla.redhat.com/1372576
---
src/logging/virtlogd.service.in | 1 -
src/logging/virtlogd.socket.in | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/logging/virtlogd.service.in b/src/logging/virtlogd.service.in
index 8287994..09e0740 100644
--- a/src/logging/virtlogd.service.in
+++ b/src/logging/virtlogd.service.in
@@ -2,7 +2,6 @@
Description=Virtual machine log manager
Requires=virtlogd.socket
Before=libvirtd.service
-PartOf=libvirtd.service
Documentation=man:virtlogd(8)
Documentation=http://libvirt.org
diff --git a/src/logging/virtlogd.socket.in b/src/logging/virtlogd.socket.in
index efb6504..22b9360 100644
--- a/src/logging/virtlogd.socket.in
+++ b/src/logging/virtlogd.socket.in
@@ -1,7 +1,6 @@
[Unit]
Description=Virtual machine log manager socket
Before=libvirtd.service
-PartOf=libvirtd.service
[Socket]
ListenStream=@localstatedir@/run/libvirt/virtlogd-sock
--
2.7.4
2
2
[libvirt] [PATCH v3 0/8] Introduce aliases for virt-admin's srv-* commands
by Erik Skultety 20 Sep '16
by Erik Skultety 20 Sep '16
20 Sep '16
the original version:
https://www.redhat.com/archives/libvir-list/2016-September/msg00312.html
v2: https://www.redhat.com/archives/libvir-list/2016-September/msg00380.html
Since this series (compared to v2) does a tiny bit of refactor (tweaking might
be a better word in this case) as well, I was also looking into refactoring the
parser in vsh.c....again...And again I gave up on doing that (this time a lot
faster though) because that would mean to rewrite a lot of code mainly to enable
usage of our virString* methods. I also found an ANSI C GNU-styled command line
parser library [1] which might even cope with our command and option aliases
(I didn't look into that much though, so take it with a grain of salt).
However, though looking good, it would most likely hit the wall once it
encountered our "multi-command" feature in the interactive shell mode :(
[1] http://argtable.sourceforge.net/
since v1:
- tweaked the virsh-self-test so that it also checks the aliased commands
instead of skipping them (since there was a good reason for that before
the changes this series introduces)
- patches (now) 7-8 remained untouched
since v2:
- Michal was indeed right about having a proper check for missing aliases
which would eventually result in a reasonable internal error
- so the check was put into vshCmddefCheckInternals, but that function
should not be called from within vshCmddefOptParse because it's not just
about checking the .opts but the overall command structure and at the time
of parsing the arguments we should already know whether the command
structure is valid or not
- since vshCmddefOptParse has been split once again, merge it with
vshCmddefOptFill and drop the latter
Erik Skultety (8):
vsh: Fix NULL dereference leading to SIGSEGV if a command is missing
'.info'
vsh: vshCmddefHelp: Drop the unnecessary 'else' branch
vsh: vshCmddefHelp: Retrieve command info after we know the command is
non-NULL
vsh: Extract vshCmddefCheckInternals from vshCmddefOptParse
vsh: discard vshCmddefOptFill and move its body to vshCmddefOptParse
virt-admin: Tweak command parsing logic so that aliases point to new
commands
virt-admin: Add some command aliases to provide syntax sugar over ugly
commands
virt-admin: Replace the (now) aliases with new command names in the
man page
tools/virsh-nodedev.c | 6 +-
tools/virsh.pod | 2 -
tools/virt-admin.c | 24 +++++
tools/virt-admin.pod | 30 +++---
tools/vsh.c | 280 ++++++++++++++++++++++++++------------------------
tools/vsh.h | 4 +-
6 files changed, 191 insertions(+), 155 deletions(-)
--
2.5.5
2
22
[libvirt] [PATCH v3 0/2] qemu/gluster: add option for tuning debug logging level
by Prasanna Kumar Kalever 20 Sep '16
by Prasanna Kumar Kalever 20 Sep '16
20 Sep '16
v3:
Add patch 2/2 which address capability checks
Changed 'glusterfs_debug_level' to 'gluster_debug_level' agreeing to Peter
Made changes in libvirtd_qemu.aug
Thanks to Peter & Daniel
v2:
Modify test cases and syntax check changes as suggested by Peter in v1.
Rename qemu_gfapi_debuglevel to glusterfs_debug_level as per Daniel comments.
Fix to make debug_level changes effects on URI along with JSON.
TODO:
* changes in libvirtd_qemu.aug
Which I don't understand for now
* comment on debug_level variable in storage source
Not sure what is the right place
* Capablities check
v1:
Initial post
Prasanna Kumar Kalever (2):
qemu/gluster: add option for tuning debug logging level
qemu_capabilities: Introduce gluster specific debug capability
src/qemu/libvirtd_qemu.aug | 3 +++
src/qemu/qemu.conf | 20 ++++++++++++++++++++
src/qemu/qemu_capabilities.c | 6 ++++++
src/qemu/qemu_capabilities.h | 3 +++
src/qemu/qemu_command.c | 21 ++++++++++++++++++---
src/qemu/qemu_conf.c | 3 +++
src/qemu/qemu_conf.h | 1 +
src/util/virstoragefile.h | 2 ++
.../qemuargv2xml-disk-drive-network-gluster.args | 7 ++++---
.../qemuxml2argv-disk-drive-network-gluster.args | 12 ++++++------
tests/qemuxml2argvtest.c | 3 ++-
11 files changed, 68 insertions(+), 13 deletions(-)
--
2.7.4
3
5
20 Sep '16
The recent update to gnulib
commit 9d7a37ecb2ab516c19164a57b8aeb32016a99d2c
Author: Eric Blake <eblake(a)redhat.com>
Date: Thu Sep 15 15:12:52 2016 -0500
build: update to latest gnulib
Pulled in a change that adds -fno-common to the default compiler
flags
commit bf8e658ffadb95d444f56d222d04c9af955af765
Author: Jim Meyering <meyering(a)fb.com>
Date: Fri Sep 2 09:16:16 2016 -0700
manywarnings: add -fno-common
This caused libvirt Mingw build to break with the compiler
reporting 100's of definitions of virConnectAuthPtrDefault
./.libs/libvirt_util.a(libvirt_util_la-virarch.o):virarch.c:(.bss+0x0): multiple definition of `virConnectAuthPtrDefault'
./.libs/libvirt_util.a(libvirt_util_la-viralloc.o):viralloc.c:(.bss+0x0): first defined here
./.libs/libvirt_util.a(libvirt_util_la-viratomic.o):viratomic.c:(.bss+0x0): multiple definition of `virConnectAuthPtrDefault'
./.libs/libvirt_util.a(libvirt_util_la-viralloc.o):/home/berrange/src/virt/libvirt/src/util/viralloc.c:87: first defined here
./.libs/libvirt_util.a(libvirt_util_la-viraudit.o):viraudit.c:(.bss+0x0): multiple definition of `virConnectAuthPtrDefault'
./.libs/libvirt_util.a(libvirt_util_la-viralloc.o):/home/berrange/src/virt/libvirt/src/util/viralloc.c:87: first defined here
./.libs/libvirt_util.a(libvirt_util_la-virauth.o):virauth.c:(.bss+0x0): multiple definition of `virConnectAuthPtrDefault'
./.libs/libvirt_util.a(libvirt_util_la-viralloc.o):/home/berrange/src/virt/libvirt/src/util/viralloc.c:87: first defined here
./.libs/libvirt_util.a(libvirt_util_la-virauthconfig.o):virauthconfig.c:(.bss+0x0): multiple definition of `virConnectAuthPtrDefault'
...snip...
The cause is our VIR_EXPORT_VAR macro which has some
magic on win to add dllexport/dllimport to the variable
declaration. Unfortunately the dllexport branch missed
off the 'extern' keyword, so the header file was in
fact declaring an instance of the variable in every
source file.
Previously the linker would merge all these definitions
into one, but that no longer happens due to -fno-common
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
Pushing as a CI build fix
include/libvirt/libvirt-common.h.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-common.h.in b/include/libvirt/libvirt-common.h.in
index 79bfe90..0e8ada4 100644
--- a/include/libvirt/libvirt-common.h.in
+++ b/include/libvirt/libvirt-common.h.in
@@ -49,7 +49,7 @@ extern "C" {
# define VIR_EXPORT_VAR extern
# else
# ifdef IN_LIBVIRT
-# define VIR_EXPORT_VAR __declspec(dllexport)
+# define VIR_EXPORT_VAR __declspec(dllexport) extern
# else
# define VIR_EXPORT_VAR __declspec(dllimport) extern
# endif
--
2.7.4
1
0
20 Sep '16
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
.../qemucapabilitiesdata/caps_2.7.0.x86_64.replies | 39 ++++++++++++++++------
1 file changed, 29 insertions(+), 10 deletions(-)
diff --git a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.replies
index 7986dae..ce8dee9 100644
--- a/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.replies
+++ b/tests/qemucapabilitiesdata/caps_2.7.0.x86_64.replies
@@ -2,11 +2,11 @@
"QMP": {
"version": {
"qemu": {
- "micro": 91,
- "minor": 6,
+ "micro": 0,
+ "minor": 7,
"major": 2
},
- "package": " (v2.7.0-rc1-52-g42e0d60)"
+ "package": " (v2.7.0)"
},
"capabilities": [
]
@@ -22,11 +22,11 @@
{
"return": {
"qemu": {
- "micro": 91,
- "minor": 6,
+ "micro": 0,
+ "minor": 7,
"major": 2
},
- "package": " (v2.7.0-rc1-52-g42e0d60)"
+ "package": " (v2.7.0)"
},
"id": "libvirt-2"
}
@@ -466,7 +466,7 @@
{
"return": {
- "fd": 14,
+ "fd": 13,
"fdset-id": 0
},
"id": "libvirt-5"
@@ -696,6 +696,9 @@
"name": "container"
},
{
+ "name": "qio-channel-rdma"
+ },
+ {
"name": "host-x86_64-cpu"
},
{
@@ -1245,6 +1248,9 @@
"name": "nvdimm"
},
{
+ "name": "virtio-balloon-pci"
+ },
+ {
"name": "SandyBridge-x86_64-cpu"
},
{
@@ -1254,6 +1260,9 @@
"name": "virtio-balloon-device"
},
{
+ "name": "ccid-card-passthru"
+ },
+ {
"name": "qxl"
},
{
@@ -1335,7 +1344,7 @@
"name": "tls-creds-x509"
},
{
- "name": "virtio-balloon-pci"
+ "name": "ccid-card-emulated"
},
{
"name": "ISA"
@@ -3176,7 +3185,7 @@
"type": "bool"
},
{
- "name": "any_layout",
+ "name": "event_idx",
"description": "on/off",
"type": "bool"
},
@@ -3191,6 +3200,11 @@
"type": "bool"
},
{
+ "name": "stats",
+ "description": "on/off",
+ "type": "bool"
+ },
+ {
"name": "multifunction",
"description": "on/off",
"type": "bool"
@@ -3206,7 +3220,7 @@
"type": "bool"
},
{
- "name": "event_idx",
+ "name": "virgl",
"description": "on/off",
"type": "bool"
},
@@ -3248,6 +3262,11 @@
"type": "int32"
},
{
+ "name": "any_layout",
+ "description": "on/off",
+ "type": "bool"
+ },
+ {
"name": "max_outputs",
"type": "uint32"
},
--
2.10.0
2
2
20 Sep '16
https://bugzilla.redhat.com/show_bug.cgi?id=1227354
v1: https://www.redhat.com/archives/libvir-list/2016-July/msg01235.html
v2: https://www.redhat.com/archives/libvir-list/2016-August/msg00412.html
* probe for the qemu capability
* add the attribute to virtio1-only devices such as virtio-gpu
and virtio-input devices
* allow multiple revisions to be specified
v3:
* touch up documentation
* rename the capability from "virtio-revision" to "virtio-disable-legacy"
* move the formatting in qemuBuildNicDevStr after the address
and only do it for virtio
* get rid of novelty enum names
v4:
* only probe the capability for PCI devices
v5:
* instead of a separate element, use one attribute under the driver
element
Ján Tomko (13):
Use a separate buffer for <input> subelements
Use a separate buffer for <disk><driver>
Use a separate buffer for <controller><driver>
Use a separate buffer for <filesystem><driver>
Add compatibility attribute to memballoon
Add compatibility attribute to disks
Add compatibility attribute to controllers
Add compatibility attribute to filesystems
Add compatibility attribute to interfaces
Add compatibility attribute to rng devices
Add compatibility attribute to video
Add compatibility attribute to input devices
qemu: format options for enforcing virtio revisions
docs/formatdomain.html.in | 60 +++++-
docs/schemas/domaincommon.rng | 42 ++++
src/conf/domain_conf.c | 220 +++++++++++++++------
src/conf/domain_conf.h | 17 ++
src/qemu/qemu_command.c | 70 +++++++
.../qemuxml2argv-virtio-revision.args | 62 ++++++
.../qemuxml2argv-virtio-revision.xml | 109 ++++++++++
tests/qemuxml2argvtest.c | 11 ++
.../qemuxml2xmlout-virtio-revision.xml | 108 ++++++++++
tests/qemuxml2xmltest.c | 2 +
10 files changed, 641 insertions(+), 60 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-revision.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-revision.xml
create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-virtio-revision.xml
--
2.7.3
9
36
From: Chen Hanxiao <chenhanxiao(a)gmail.com>
s/unitl/until
Signed-off-by: Chen Hanxiao <chenhanxiao(a)gmail.com>
---
src/qemu/qemu_process.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index cecd321..1f56883 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1678,7 +1678,7 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
}
/* Hold an extra reference because we can't allow 'vm' to be
- * deleted unitl the monitor gets its own reference. */
+ * deleted until the monitor gets its own reference. */
virObjectRef(vm);
ignore_value(virTimeMillisNow(&priv->monStart));
--
1.8.3.1
2
1
Commit 8563560026d192c2cf047b550ffd468692245ed6 switched from
hardcoded use of strcontent to hardcoded use of fixedcontent
(fixedcontent is *sometimes* a copy of strcontent with a \n
appended). This was a problem because sometimes fixedcontent is *not*
a copy of strcontent, but is instead NULL, leading to the regenerated
test case output being a 0 length file.
This patch creates a new const char *cmpcontent initialized to
strcontent, but changed to fixedcontent if/when fixedcontent is
created, then always uses cmpcontent instead of (str|fixed)content.
---
tests/testutils.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/tests/testutils.c b/tests/testutils.c
index f87628e..c934785 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -694,6 +694,7 @@ virTestCompareToFile(const char *strcontent,
int ret = -1;
char *filecontent = NULL;
char *fixedcontent = NULL;
+ const char *cmpcontent = strcontent;
if (virTestLoadFile(filename, &filecontent) < 0 && !virTestGetRegenerate())
goto failure;
@@ -703,13 +704,13 @@ virTestCompareToFile(const char *strcontent,
strcontent[strlen(strcontent) - 1] != '\n') {
if (virAsprintf(&fixedcontent, "%s\n", strcontent) < 0)
goto failure;
+ cmpcontent = fixedcontent;
}
- if (STRNEQ_NULLABLE(fixedcontent ? fixedcontent : strcontent,
- filecontent)) {
+ if (STRNEQ_NULLABLE(cmpcontent, filecontent)) {
virTestDifferenceFull(stderr,
filecontent, filename,
- fixedcontent, NULL);
+ cmpcontent, NULL);
goto failure;
}
--
2.7.4
2
1
Now that autoconf and gnulib have worked around the glibc 2.25
issue, we don't need our hack any more. I'll probably push in
24 hours under the gnulib-maintenance rule, if I don't get a
review first.
Eric Blake (2):
build: update to latest gnulib
Revert "configure: Check for major() more strictly"
.gnulib | 2 +-
configure.ac | 3 ---
2 files changed, 1 insertion(+), 4 deletions(-)
--
2.7.4
1
3
[libvirt] [python PATCH] override: Properly override wrapper for virDomainGetGuestVcpus
by Peter Krempa 19 Sep '16
by Peter Krempa 19 Sep '16
19 Sep '16
Without the change to libvirt-override-api.xml generator.py would
generate the following function header:
def guestVcpus(self, params, nparams, flags=0):
Since @params and @nparams are output-only in C and the python C
implementation actualy creates a dict from them we should not need to
pass them. Add the API definition to drop the two unnecessary args:
def guestVcpus(self, flags=0):
The code did not work at all until this change as the C impl expects
only two arguments but the python required use of four.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1377071
---
libvirt-override-api.xml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml
index 49de122..50250bc 100644
--- a/libvirt-override-api.xml
+++ b/libvirt-override-api.xml
@@ -698,5 +698,11 @@
<arg name='flags' type='unsigned int' info='extra flags; not used yet, so callers should always pass 0'/>
<return type='char *' info="dictionary of domain interfaces along with their MAC and IP addresses"/>
</function>
+ <function name='virDomainGetGuestVcpus' file='python'>
+ <info>returns a dictionary containing information regarding guest vcpus</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='flags' type='unsigned int' info='extra flags; not used yet, so callers should always pass 0'/>
+ <return type='int' info="dictionary of vcpu data returned by the guest agent"/>
+ </function>
</symbols>
</api>
--
2.10.0
2
1
So I've tried to migrate a guest recently (to answer a needinfo
for some bug of mine). Meanwhile, I've ran into many problems and
bugs we have (apparently nobody tried migrations lately). Here's
the first round of patches.
Second round will require proper deep copy function for
virDomainDef struct.
Michal Privoznik (2):
qemuBuildMemoryBackendStr: Don't crash if no hugetlbfs is mounted
qemu: Introduce qemuGetHupageMemPath
src/qemu/qemu_command.c | 57 +++++--------------------------------------------
src/qemu/qemu_conf.c | 50 +++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_conf.h | 4 ++++
3 files changed, 59 insertions(+), 52 deletions(-)
--
2.8.4
2
8
19 Sep '16
From: Chen Hanxiao <chenhanxiao(a)gmail.com>
Both qemu monitor and agent print the same
log on HUANGUP event, which woud be confused
when reading libvirtd log.
This patch will give a different log for them.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)gmail.com>
---
src/qemu/qemu_agent.c | 2 +-
src/qemu/qemu_monitor.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index eeede6b..babd8f2 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -633,7 +633,7 @@ qemuAgentIO(int watch, int fd, int events, void *opaque)
if (!error &&
events & VIR_EVENT_HANDLE_HANGUP) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("End of file from monitor"));
+ _("End of file from agent monitor"));
eof = true;
events &= ~VIR_EVENT_HANDLE_HANGUP;
}
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 4171914..d92a359 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -692,7 +692,7 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque)
hangup = true;
if (!error) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("End of file from monitor"));
+ _("End of file from qemu monitor"));
eof = true;
events &= ~VIR_EVENT_HANDLE_HANGUP;
}
--
1.8.3.1
2
1
19 Sep '16
The layout in $HOME/.pki is different from that in /etc/pki
but we never tell anyone about this trap. Add docs showing
the required $HOME/.pki layout.
---
docs/remote.html.in | 41 ++++++++++++++++++++++++++++++++++-------
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/docs/remote.html.in b/docs/remote.html.in
index 9b132f1..4c3012f 100644
--- a/docs/remote.html.in
+++ b/docs/remote.html.in
@@ -419,13 +419,21 @@ next section.
<td>
<code>/etc/pki/CA/cacert.pem</code>
</td>
- <td> Installed on all clients and servers </td>
+ <td> Installed on the client and server </td>
<td> CA's certificate (<a href="#Remote_TLS_CA">more info</a>)</td>
<td> n/a </td>
</tr>
<tr>
<td>
- <code>/etc/pki/libvirt/ private/serverkey.pem</code>
+ <code>$HOME/.pki/cacert.pem</code>
+ </td>
+ <td> Installed on the client </td>
+ <td> CA's certificate (<a href="#Remote_TLS_CA">more info</a>)</td>
+ <td> n/a </td>
+ </tr>
+ <tr>
+ <td>
+ <code>/etc/pki/libvirt/private/serverkey.pem</code>
</td>
<td> Installed on the server </td>
<td> Server's private key (<a href="#Remote_TLS_server_certificates">more info</a>)</td>
@@ -433,7 +441,7 @@ next section.
</tr>
<tr>
<td>
- <code>/etc/pki/libvirt/ servercert.pem</code>
+ <code>/etc/pki/libvirt/servercert.pem</code>
</td>
<td> Installed on the server </td>
<td> Server's certificate signed by the CA.
@@ -443,7 +451,26 @@ next section.
</tr>
<tr>
<td>
- <code>/etc/pki/libvirt/ private/clientkey.pem</code>
+ <code>/etc/pki/libvirt/private/clientkey.pem</code>
+ </td>
+ <td> Installed on the client </td>
+ <td> Client's private key. (<a href="#Remote_TLS_client_certificates">more info</a>) </td>
+ <td> n/a </td>
+ </tr>
+ <tr>
+ <td>
+ <code>/etc/pki/libvirt/clientcert.pem</code>
+ </td>
+ <td> Installed on the client </td>
+ <td> Client's certificate signed by the CA
+ (<a href="#Remote_TLS_client_certificates">more info</a>) </td>
+ <td> Distinguished Name (DN) can be checked against an access
+ control list (<code>tls_allowed_dn_list</code>).
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <code>$HOME/.pki/libvirt/clientkey.pem</code>
</td>
<td> Installed on the client </td>
<td> Client's private key. (<a href="#Remote_TLS_client_certificates">more info</a>) </td>
@@ -451,7 +478,7 @@ next section.
</tr>
<tr>
<td>
- <code>/etc/pki/libvirt/ clientcert.pem</code>
+ <code>$HOME/.pki/libvirt/clientcert.pem</code>
</td>
<td> Installed on the client </td>
<td> Client's certificate signed by the CA
@@ -469,7 +496,7 @@ next section.
</p>
<ul>
<li> For a non-root user, libvirt tries to find the certificates
- in $HOME/.pki/libvirt. If the required CA certificate cannot
+ in $HOME/.pki/libvirt first. If the required CA certificate cannot
be found, then the global default location
(/etc/pki/CA/cacert.pem) will be used.
Likewise, if either the client certificate
@@ -477,7 +504,7 @@ next section.
locations (/etc/pki/libvirt/clientcert.pem,
/etc/pki/libvirt/private/clientkey.pem) will be used.
</li>
- <li> For the root user, the global default locations will be used.</li>
+ <li> For the root user, the global default locations will always be used.</li>
</ul>
<h4>
<a name="Remote_TLS_background">Background to TLS certificates</a>
--
2.7.4
2
1
[libvirt] [PATCH 00/20] 20 crazy IVSHMEM patches you won't believe compile
by Martin Kletzander 19 Sep '16
by Martin Kletzander 19 Sep '16
19 Sep '16
Let's see if the subject works if one is in need of reviews =)
Yet another qemu device, right? We even have an existing device for
that, right? That should be pretty straight-forward and easy, right?
Well, let's see... I, at least, tried splitting the patches for you
to be as easy to review as possible.
Just in case you're trying out the hot-(un)plug on an upstream QEMU,
make sure you do it on i440fx machine, not on q35 one, otherwise it
will not work nicely (or rather at all).
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1347049
Martin Kletzander (20):
qemuhotplugtest: Only read result_filename if used
schema: Allow shmem to have alias
conf: Allow copying of shmem defs
conf: Add support for shmem model
conf: Add support for shmem role
qemu: Add support for shmem role
qemu: Add newer shmem models
qemu: Add capabilities for ivshmem-{plain,doorbell}
qemu: Save various defaults for shmem
qemu: Disable migration for shmem with peer role
qemu: Make qemuBuildShmemDevStr static
qemu: Rename qemuBuildShmemDevStr to qemuBuildShmemDevLegacyStr
qemu: Move common checks outside qemuBuildShmemDevLegacyStr
qemu: Reorder shmem params nicely
qemu: Abstract shmem socket path preparation
qemu: Rename qemuBuildShmemBackendStr to qemuBuildShmemBackendChrStr
qemu: Support newer ivshmem device variants
qemu: Add qemuAssignDeviceShmemAlias and use it
conf: Add some shmem helpers for future use
qemu: Add support for hot/cold-(un)plug of shmem devices
docs/formatdomain.html.in | 10 +-
docs/schemas/domaincommon.rng | 22 ++
src/conf/domain_conf.c | 154 ++++++++++++-
src/conf/domain_conf.h | 30 +++
src/libvirt_private.syms | 9 +
src/qemu/qemu_alias.c | 32 ++-
src/qemu/qemu_alias.h | 4 +
src/qemu/qemu_capabilities.c | 4 +
src/qemu/qemu_capabilities.h | 2 +
src/qemu/qemu_command.c | 245 ++++++++++++++++----
src/qemu/qemu_command.h | 14 +-
src/qemu/qemu_domain.c | 46 ++++
src/qemu/qemu_domain.h | 3 +
src/qemu/qemu_driver.c | 39 +++-
src/qemu/qemu_hotplug.c | 247 ++++++++++++++++++++-
src/qemu/qemu_hotplug.h | 6 +
src/qemu/qemu_migration.c | 13 ++
.../caps_2.6.0-gicv2.aarch64.xml | 2 +
.../caps_2.6.0-gicv3.aarch64.xml | 2 +
tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 2 +
tests/qemucapabilitiesdata/caps_2.6.0.x86_64.xml | 2 +
tests/qemucapabilitiesdata/caps_2.7.0.x86_64.xml | 2 +
tests/qemuhotplugtest.c | 23 +-
.../qemuhotplug-ivshmem-doorbell-detach.xml | 7 +
.../qemuhotplug-ivshmem-doorbell.xml | 4 +
.../qemuhotplug-ivshmem-plain-detach.xml | 6 +
.../qemuhotplug-ivshmem-plain.xml | 3 +
...muhotplug-base-live+ivshmem-doorbell-detach.xml | 1 +
.../qemuhotplug-base-live+ivshmem-doorbell.xml | 65 ++++++
.../qemuhotplug-base-live+ivshmem-plain-detach.xml | 1 +
.../qemuhotplug-base-live+ivshmem-plain.xml | 58 +++++
.../qemuxml2argv-shmem-plain-doorbell.args | 46 ++++
...m.xml => qemuxml2argv-shmem-plain-doorbell.xml} | 15 +-
tests/qemuxml2argvdata/qemuxml2argv-shmem.args | 16 +-
tests/qemuxml2argvdata/qemuxml2argv-shmem.xml | 6 +-
tests/qemuxml2argvtest.c | 3 +
...xml => qemuxml2xmlout-shmem-plain-doorbell.xml} | 24 +-
tests/qemuxml2xmloutdata/qemuxml2xmlout-shmem.xml | 15 +-
tests/qemuxml2xmltest.c | 2 +
39 files changed, 1092 insertions(+), 93 deletions(-)
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell-detach.xml
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-doorbell.xml
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
create mode 120000 tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell-detach.xml
create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
create mode 120000 tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain-detach.xml
create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
copy tests/qemuxml2argvdata/{qemuxml2argv-shmem.xml => qemuxml2argv-shmem-plain-doorbell.xml} (78%)
copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-shmem.xml => qemuxml2xmlout-shmem-plain-doorbell.xml} (78%)
--
2.10.0
2
52
[libvirt] [PATCH] qemu-migration: Disallow migration of read only disk
by Corey S. McQuay 19 Sep '16
by Corey S. McQuay 19 Sep '16
19 Sep '16
Currently Libvirt allows attempts to migrate read only disks. Qemu cannot handle this as read only
disks cannot be written to on the destination system. The end result is a cryptic error message
and a failed migration.
This patch causes migration to fail earlier and provides a meaningful error message stating that
migrating read only disks is not supported.
Signed-off-by: Corey S. McQuay <csmcquay(a)linux.vnet.ibm.com>
Reviewed-by: Jason J. Herne <jjherne(a)linux.vnet.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
---
src/qemu/qemu_migration.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index e451ef6..3311711 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -2392,6 +2392,28 @@ qemuMigrationIsSafe(virDomainDefPtr def,
return true;
}
+static bool
+qemuMigrationAreAllDisksRW(virDomainDefPtr def,
+ size_t nmigrate_disks,
+ const char **migrate_disks)
+{
+ size_t i;
+
+ for (i = 0; i < def->ndisks; i++) {
+ virDomainDiskDefPtr disk = def->disks[i];
+
+ if (qemuMigrateDisk(disk, nmigrate_disks, migrate_disks) &&
+ disk->src->readonly) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+ _("Cannot migrate read-only disk %s"),
+ disk->dst);
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** qemuMigrationSetOffline
* Pause domain for non-live migration.
*/
@@ -3137,6 +3159,9 @@ qemuMigrationBeginPhase(virQEMUDriverPtr driver,
!qemuMigrationIsSafe(vm->def, nmigrate_disks, migrate_disks))
goto cleanup;
+ if (!qemuMigrationAreAllDisksRW(vm->def, nmigrate_disks, migrate_disks))
+ goto cleanup;
+
if (flags & VIR_MIGRATE_POSTCOPY &&
(!(flags & VIR_MIGRATE_LIVE) ||
flags & VIR_MIGRATE_PAUSED)) {
--
2.7.4
3
3
I'm getting warnings about it - I assume it needs renewal.
TIA,
Y.
2
1
17 Sep '16
Since this is something between PV and HVM, it makes sense to put the
setting in place where domain type is specified.
To enable it, use <os><type machine="xenpvh">...</type></os>. It is
also included in capabilities.xml, for every supported HVM guest type - it
doesn't seems to be any other requirement (besides new enough Xen).
Signed-off-by: Marek Marczykowski-Górecki <marmarek(a)invisiblethingslab.com>
---
src/libxl/libxl_capabilities.c | 40 +++++++++++++++++++++++++++++++---------
src/libxl/libxl_conf.c | 2 ++
src/libxl/libxl_driver.c | 6 ++++--
3 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/src/libxl/libxl_capabilities.c b/src/libxl/libxl_capabilities.c
index 0145116..c443353 100644
--- a/src/libxl/libxl_capabilities.c
+++ b/src/libxl/libxl_capabilities.c
@@ -45,11 +45,16 @@ VIR_LOG_INIT("libxl.libxl_capabilities");
/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
#define LIBXL_X86_FEATURE_PAE_MASK 0x40
+enum machine_type {
+ machine_hvm,
+ machine_pvh,
+ machine_pv,
+};
struct guest_arch {
virArch arch;
int bits;
- int hvm;
+ enum machine_type machine;
int pae;
int nonpae;
int ia64_be;
@@ -296,7 +301,7 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps)
/* Search for existing matching (model,hvm) tuple */
for (i = 0; i < nr_guest_archs; i++) {
if ((guest_archs[i].arch == arch) &&
- guest_archs[i].hvm == hvm)
+ guest_archs[i].machine == (hvm ? machine_hvm : machine_pv))
break;
}
@@ -308,7 +313,7 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps)
nr_guest_archs++;
guest_archs[i].arch = arch;
- guest_archs[i].hvm = hvm;
+ guest_archs[i].machine = hvm ? machine_hvm : machine_pv;
/* Careful not to overwrite a previous positive
setting with a negative one here - some archs
@@ -320,23 +325,40 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps)
guest_archs[i].nonpae = nonpae;
if (ia64_be)
guest_archs[i].ia64_be = ia64_be;
+
+ /* On Xen >= 4.4 add PVH for each HVM guest, and do it only once */
+ if ((ver_info->xen_version_major > 4 ||
+ (ver_info->xen_version_major == 4 &&
+ ver_info->xen_version_minor >= 4)) &&
+ hvm && i == nr_guest_archs-1) {
+ i = nr_guest_archs;
+ /* Too many arch flavours - highly unlikely ! */
+ if (i >= ARRAY_CARDINALITY(guest_archs))
+ continue;
+ nr_guest_archs++;
+ guest_archs[i].arch = arch;
+ guest_archs[i].machine = machine_pvh;
+ }
}
}
regfree(®ex);
for (i = 0; i < nr_guest_archs; ++i) {
virCapsGuestPtr guest;
- char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"};
+ char const *const xen_machines[] = {
+ guest_archs[i].machine == machine_hvm ? "xenfv" :
+ (guest_archs[i].machine == machine_pvh ? "xenpvh" : "xenpv")};
virCapsGuestMachinePtr *machines;
if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
return -1;
if ((guest = virCapabilitiesAddGuest(caps,
- guest_archs[i].hvm ? VIR_DOMAIN_OSTYPE_HVM : VIR_DOMAIN_OSTYPE_XEN,
+ guest_archs[i].machine == machine_hvm ?
+ VIR_DOMAIN_OSTYPE_HVM : VIR_DOMAIN_OSTYPE_XEN,
guest_archs[i].arch,
LIBXL_EXECBIN_DIR "/qemu-system-i386",
- (guest_archs[i].hvm ?
+ (guest_archs[i].machine == machine_hvm ?
LIBXL_FIRMWARE_DIR "/hvmloader" :
NULL),
1,
@@ -375,7 +397,7 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps)
0) == NULL)
return -1;
- if (guest_archs[i].hvm) {
+ if (guest_archs[i].machine != machine_pv) {
if (virCapabilitiesAddGuestFeature(guest,
"acpi",
1,
@@ -390,7 +412,7 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps)
if (virCapabilitiesAddGuestFeature(guest,
"hap",
1,
- 1) == NULL)
+ guest_archs[i].machine == machine_hvm) == NULL)
return -1;
}
}
@@ -409,7 +431,7 @@ libxlMakeDomainOSCaps(const char *machine,
os->supported = true;
- if (STREQ(machine, "xenpv"))
+ if (STREQ(machine, "xenpv") || STREQ(machine, "xenpvh"))
return 0;
capsLoader->supported = true;
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index 5202ca1..aa06586 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -173,6 +173,8 @@ libxlMakeDomCreateInfo(libxl_ctx *ctx,
}
} else {
c_info->type = LIBXL_DOMAIN_TYPE_PV;
+ if (STREQ(def->os.machine, "xenpvh"))
+ libxl_defbool_set(&c_info->pvh, true);
}
if (VIR_STRDUP(c_info->name, def->name) < 0)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 4957072..fa58346 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -6321,9 +6321,11 @@ libxlConnectGetDomainCapabilities(virConnectPtr conn,
emulatorbin = "/usr/bin/qemu-system-x86_64";
if (machine) {
- if (STRNEQ(machine, "xenpv") && STRNEQ(machine, "xenfv")) {
+ if (STRNEQ(machine, "xenpv") &&
+ STRNEQ(machine, "xenpvh") &&
+ STRNEQ(machine, "xenfv")) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
- _("Xen only supports 'xenpv' and 'xenfv' machines"));
+ _("Xen only supports 'xenpv', 'xenpvh' and 'xenfv' machines"));
goto cleanup;
}
} else {
--
2.5.5
>From marmarek(a)invisiblethingslab.com Fri Aug 5 20:06:26 2016
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= <marmarek(a)invisiblethingslab.com>
To: libvir-list(a)redhat.com
Cc: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= <marmarek(a)invisiblethingslab.com>
Subject: [PATCH 2/2] libxl: set shadow memory for any guest type, not only HVM
Date: Fri, 5 Aug 2016 20:05:44 +0200
Message-Id: <1470420344-7693-2-git-send-email-marmarek(a)invisiblethingslab.com>
X-Mailer: git-send-email 2.5.5
In-Reply-To: <1470420344-7693-1-git-send-email-marmarek(a)invisiblethingslab.com>
References: <1470420344-7693-1-git-send-email-marmarek(a)invisiblethingslab.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Organization: Invisible Things Lab
Content-Transfer-Encoding: 8bit
Otherwise starting PVH guest will result in "arch_setup_bootlate:
mapping shared_info failed (pfn=..., rc=-1, errno: 12): Internal error".
After this change the behaviour is the same as in `xl`.
Signed-off-by: Marek Marczykowski-Górecki <marmarek(a)invisiblethingslab.com>
---
src/libxl/libxl_conf.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index aa06586..155934c 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -494,11 +494,6 @@ libxlMakeDomBuildInfo(virDomainDefPtr def,
}
}
}
-
- /* Allow libxl to calculate shadow memory requirements */
- b_info->shadow_memkb =
- libxl_get_required_shadow_memory(b_info->max_memkb,
- b_info->max_vcpus);
} else {
/*
* For compatibility with the legacy xen toolstack, default to pygrub
@@ -528,6 +523,11 @@ libxlMakeDomBuildInfo(virDomainDefPtr def,
return -1;
}
+ /* Allow libxl to calculate shadow memory requirements */
+ b_info->shadow_memkb =
+ libxl_get_required_shadow_memory(b_info->max_memkb,
+ b_info->max_vcpus);
+
return 0;
}
--
2.5.5
2
5
This patch series does several things:
- fixes tests to avoid relying on bugs in our code
- adds support for advertising supported CPU modes and models in domain
capabilities
- starts adding better and higher level APIs to our cpu driver (the old
low level APIs will be removed once this process is over)
- prepares qemu driver for asking QEMU what a host CPU looks like and
what CPU models can be run on it
- makes QEMU CPU command line builder build command line and nothing
else
The added part of domain capabilities XML looks like this:
<cpu>
<mode name='host-passthrough' supported='yes'/>
<mode name='host-model' supported='yes'>
<model fallback='allow'>Broadwell</model>
<vendor>Intel</vendor>
<feature policy='disable' name='aes'/>
<feature policy='require' name='vmx'/>
</mode>
<mode name='custom' supported='yes'>
<model>Broadwell</model>
<model>Broadwell-noTSX</model>
...
</mode>
</cpu>
and host-passthrough is only advertised as supported for KVM domains,
host-model is only supported when guest architecture is compatible with
host and overall it should just work the way one would expect (in
contrast to the current state of the code).
Big thanks for any comments and review in advance and...
Enjoy my PTO :-)
Jiri Denemark (41):
cpuGetModels: Switch to virArch
domcaps: Add support for listing supported CPU models
qemu: Use virDomainCapsCPUModels for cpuDefinitions
qemuxml2argvtest: Rename extraFlags as qemuCaps
qemuxml2argvtest: Rename "out" labels as "cleanup"
qemuxml2argvtest: Get rid of testCompareXMLToArgvHelper
qemuxml2argvtest: Reorder functions
qemuxml2argvtest: Update qemuCaps after parsing domain XML
qemuxml2argvtest: Properly initialize qemuCaps->arch
testutilsqemu: Helpers for changing host CPU and arch
qemu: Separate guest CPU validation from command line creation
qemuxml2argvtest: Properly setup CPU models in qemuCaps
qemuxml2argvtest: Set correct architecture for KVM guests
qemuxml2argvtest: Reorder CPU features
qemu: Introduce virQEMUCapsGuestIsNative
qemu: Fill in CPU domain capabilities
cpu: Special case models == NULL in cpuGetModels
cpu: Don't overwrite errors in cpuGetModels
domcaps: Show only CPU models supported by libvirt
domcaps: Add CPU usable flag
schema: Separate CPU related definitions into cputypes.rng
qemu: Propagate virCapsPtr to virQEMUCapsNewForBinaryInternal
conf: Introduce virCPUDefCopyWithoutModel
conf: Introduce virCPUDefMoveModel
conf: Introduce virCPUDefCopyModelFilter
qemu: Store host-model CPU in qemu capabilities
cpu: Drop false support for ARM cpu-model
Show host model in domain capabilities
qemu: Introduce virQEMUCapsGetHostModel
qemu: Introduce virQEMUCapsIsCPUModeSupported
cpu: Make x86ModelFromCPU easier to read
cpu: Make x86ModelFromCPU a bit smarter
cpu: Report error for unknown features in x86HasFeature
cpu: Add x86FeatureInData
cpu: Rework cpuUpdate
cpu: Set nfeatures_max correctly in x86Decode
cpu: Introduce virCPUTranslate
cpu: Rework cpuHasFeature
cpu: Rework cpuCompare* APIs
qemu: Update guest CPU def in live XML
Move CMT feature filtering to QEMU driver
docs/formatdomaincaps.html.in | 65 +++
docs/schemas/cputypes.rng | 135 ++++++
docs/schemas/domaincaps.rng | 60 +++
docs/schemas/domaincommon.rng | 129 +-----
po/POTFILES.in | 1 +
src/conf/cpu_conf.c | 64 ++-
src/conf/cpu_conf.h | 19 +
src/conf/domain_capabilities.c | 209 ++++++++++
src/conf/domain_capabilities.h | 47 +++
src/cpu/cpu.c | 247 ++++++++---
src/cpu/cpu.h | 72 +++-
src/cpu/cpu_arm.c | 79 ++--
src/cpu/cpu_ppc64.c | 48 ++-
src/cpu/cpu_s390.c | 1 -
src/cpu/cpu_x86.c | 463 +++++++++++++--------
src/driver-hypervisor.h | 2 +-
src/libvirt-host.c | 3 +-
src/libvirt_private.syms | 20 +-
src/qemu/qemu_capabilities.c | 387 ++++++++++++-----
src/qemu/qemu_capabilities.h | 24 +-
src/qemu/qemu_capspriv.h | 13 +-
src/qemu/qemu_command.c | 216 +++-------
src/qemu/qemu_domain.c | 32 +-
src/qemu/qemu_driver.c | 41 +-
src/qemu/qemu_monitor.c | 12 +-
src/qemu/qemu_monitor.h | 10 +-
src/qemu/qemu_monitor_json.c | 24 +-
src/qemu/qemu_monitor_json.h | 2 +-
src/qemu/qemu_parse_command.c | 2 +-
src/qemu/qemu_process.c | 95 ++++-
src/test/test_driver.c | 12 +-
src/vmware/vmware_conf.c | 6 +-
tests/cputest.c | 24 +-
.../cputestdata/x86-host+host-model-nofallback.xml | 2 +-
tests/cputestdata/x86-host+host-model.xml | 2 +-
.../x86-host+host-passthrough-features.xml | 4 +
tests/cputestdata/x86-host+host-passthrough.xml | 19 +-
tests/cputestdata/x86-host+min.xml | 27 +-
tests/cputestdata/x86-host+pentium3.xml | 39 +-
tests/cputestdata/x86-host-invtsc+host-model.xml | 2 +-
.../cputestdata/x86-host-passthrough-features.xml | 4 +
tests/domaincapsschemadata/basic.xml | 5 +
tests/domaincapsschemadata/full.xml | 12 +
tests/domaincapsschemadata/libxl-xenfv-usb.xml | 5 +
tests/domaincapsschemadata/libxl-xenfv.xml | 5 +
tests/domaincapsschemadata/libxl-xenpv-usb.xml | 5 +
tests/domaincapsschemadata/libxl-xenpv.xml | 5 +
tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 32 ++
.../qemu_2.6.0-gicv2-virt.aarch64.xml | 36 ++
.../qemu_2.6.0-gicv3-virt.aarch64.xml | 36 ++
tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 36 ++
tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 10 +
tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 36 ++
tests/domaincapstest.c | 78 +++-
tests/qemucapabilitiestest.c | 2 +-
tests/qemucapsprobe.c | 2 +-
tests/qemumonitorjsontest.c | 8 +-
.../qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml | 2 +-
.../qemuxml2argv-cpu-Haswell3.args | 2 +-
tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml | 12 +-
.../qemuxml2argv-cpu-exact2-nofallback.args | 3 +-
.../qemuxml2argv-cpu-exact2-nofallback.xml | 14 +-
.../qemuxml2argvdata/qemuxml2argv-cpu-exact2.args | 3 +-
tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml | 14 +-
.../qemuxml2argv-cpu-fallback.args | 2 +-
.../qemuxml2argv-cpu-host-model-cmt.args | 2 +-
.../qemuxml2argv-cpu-host-model-fallback.args | 2 +-
.../qemuxml2argv-cpu-minimum2.args | 2 +-
.../qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml | 6 +-
.../qemuxml2argvdata/qemuxml2argv-cpu-strict1.args | 3 +-
.../qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml | 20 +-
.../qemuxml2argv-graphics-spice-timeout.xml | 24 +-
.../qemuxml2argv-pseries-cpu-exact.args | 2 +-
.../qemuxml2argv-pseries-cpu-exact.xml | 2 +-
tests/qemuxml2argvtest.c | 312 +++++++-------
.../qemuxml2xmlout-graphics-spice-timeout.xml | 24 +-
tests/testutilsqemu.c | 126 ++++--
tests/testutilsqemu.h | 11 +-
tools/virsh-host.c | 10 +-
79 files changed, 2455 insertions(+), 1119 deletions(-)
create mode 100644 docs/schemas/cputypes.rng
create mode 100644 tests/cputestdata/x86-host+host-passthrough-features.xml
create mode 100644 tests/cputestdata/x86-host-passthrough-features.xml
--
2.9.2
2
90
16 Sep '16
Hey,
This small series implements host cpu description in caps, by getting
topology and xen hwcaps parsing done, followed by having
cpu-{compare,baseline} APIs implemented. Last thing missing I think it
would be to libxl_cpuid_set the features to enable/disable whichever
format we choose plus the appropriate XML convertion to/from XM and XL
config formats.
Note that since RFC[0] I removed the Get CPU model names API since it
would make more sense having it exported once we do support guest
cpu model/features setting. Changelog included in individual patches
(only second patch got changed)
Cheers,
Joao
[0] http://www.redhat.com/archives/libvir-list/2016-July/msg00245.html
Joao Martins (4):
libxl: describe host topology in capabilities
libxl: describe host cpu features based on hwcaps
libxl: implement virConnectCompareCPU
libxl: implement virConnectBaselineCPU
src/libxl/libxl_capabilities.c | 168 ++++++++++++++++++++++++++++++++++++++---
src/libxl/libxl_driver.c | 60 +++++++++++++++
2 files changed, 218 insertions(+), 10 deletions(-)
--
2.1.4
4
11
[libvirt] [PATCH][RFC] enable modification of xml in case of a restore forthe combination of xen/libvirt
by Guido.Rossmueller@gdata.de 16 Sep '16
by Guido.Rossmueller@gdata.de 16 Sep '16
16 Sep '16
Hello everybody,
the modification of the xml-decription of an vm is disabled in libvirt for the combination of xen/libvirt.
The following patches will enabled it.
a possible use case is the restore of a vm , whose virtuell disk is on an LVM, and it should use for the restore a snapshot of this LVM
all the best
guido
---
src/libxl/libxl_domain.c | 14 +++++++++++---
src/libxl/libxl_domain.h | 3 ++-
src/libxl/libxl_driver.c | 9 +--------
3 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 0e26b91..98992a5 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -630,7 +630,8 @@ libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver,
libxlDriverConfigPtr cfg,
const char *from,
virDomainDefPtr *ret_def,
- libxlSavefileHeaderPtr ret_hdr)
+ libxlSavefileHeaderPtr ret_hdr,
+ const char *xmlin )
{
int fd;
virDomainDefPtr def = NULL;
@@ -675,10 +676,17 @@ libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver,
goto error;
}
- if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
+ if (xmlin != NULL) {
+ if (!(def = virDomainDefParseString(xmlin, cfg->caps, driver->xmlopt,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE |
+ VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
+ goto error;
+ } else {
+ if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
VIR_DOMAIN_DEF_PARSE_INACTIVE |
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
goto error;
+ }
VIR_FREE(xml);
@@ -1072,7 +1080,7 @@ libxlDomainStart(libxlDriverPrivatePtr driver,
managed_save_fd = libxlDomainSaveImageOpen(driver, cfg,
managed_save_path,
- &def, &hdr);
+ &def, &hdr, NULL);
if (managed_save_fd < 0)
goto cleanup;
diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h
index af11a2c..863473d 100644
--- a/src/libxl/libxl_domain.h
+++ b/src/libxl/libxl_domain.h
@@ -106,7 +106,8 @@ libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver,
libxlDriverConfigPtr cfg,
const char *from,
virDomainDefPtr *ret_def,
- libxlSavefileHeaderPtr ret_hdr)
+ libxlSavefileHeaderPtr ret_hdr,
+ const char *xmlin)
ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
int
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index cb501cf..4683fe7 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -1828,14 +1828,7 @@ libxlDomainRestoreFlags(virConnectPtr conn, const char *from,
return -1;
#endif
- virCheckFlags(VIR_DOMAIN_SAVE_PAUSED, -1);
- if (dxml) {
- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
- _("xml modification unsupported"));
- return -1;
- }
-
- fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr);
+ fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr, dxml);
if (fd < 0)
goto cleanup;
--
2.6.6
____________
Virus checked by G Data MailSecurity
Version: AVA 25.8250 dated 12.09.2016
Virus news: www.antiviruslab.com
2
1
16 Sep '16
Second round of patches based on recently complete code review. Going
to submit patches in much smaller chunks, starting with this one. Future
patches will be submitted as each previous patch is reviewed and merged.
Jason Miesionczek (1):
hyperv: add new WMI classes and improve generator
src/hyperv/hyperv_wmi_generator.input | 485 ++++++++++++++++++++++++++++++++++
src/hyperv/hyperv_wmi_generator.py | 57 +++-
2 files changed, 539 insertions(+), 3 deletions(-)
--
2.7.4
2
6
16 Sep '16
The following patches include work originally done by Yves Vinter back
in 2014. The last patch introduces support for Hyper-V 2012, while still
supporting 2008. I am not sure that the method I used to include the 2012
support is the best approach, mainly due to code duplication, but I am
open to suggestions on how to do this better.
Jason Miesionczek (16):
hyperv: additional server 2008 wmi classes
hyperv: add cim types support to code generator
hyperv: add get capabilities
hyperv: implement connectGetVersion
hyperv: implement vcpu functions
hyperv: implement nodeGetFreeMemory
hyperv: implement ability to send xml soap requests
hyperv: introduce basic network driver
hyperv: add domain shutdown function
hyperv: add get scheduler functions
hyperv: add set memory functions
hyperv: set vpcu functions
hyperv: domain undefine functions
hyperv: domain define and associated functions
hyperv: network list functions
hyperv: introduce 2012 support
src/Makefile.am | 2 +
src/hyperv/hyperv_driver.c | 1989 ++++++++++++++++++++++++++++++++-
src/hyperv/hyperv_driver_2012.c | 299 +++++
src/hyperv/hyperv_driver_2012.h | 55 +
src/hyperv/hyperv_network_driver.c | 280 +++++
src/hyperv/hyperv_network_driver.h | 30 +
src/hyperv/hyperv_private.h | 8 +
src/hyperv/hyperv_wmi.c | 709 +++++++++++-
src/hyperv/hyperv_wmi.h | 78 ++
src/hyperv/hyperv_wmi_generator.input | 518 ++++++++-
src/hyperv/hyperv_wmi_generator.py | 68 +-
src/hyperv/openwsman.h | 4 +
12 files changed, 3989 insertions(+), 51 deletions(-)
create mode 100644 src/hyperv/hyperv_driver_2012.c
create mode 100644 src/hyperv/hyperv_driver_2012.h
create mode 100644 src/hyperv/hyperv_network_driver.c
create mode 100644 src/hyperv/hyperv_network_driver.h
--
2.7.4
6
47
[libvirt] [PATCH v2] qemu: map "virtio" video model to "virt" machtype correctly (arm/aarch64)
by Laszlo Ersek 16 Sep '16
by Laszlo Ersek 16 Sep '16
16 Sep '16
Most of QEMU's PCI display device models, such as:
libvirt video/model/@type QEMU -device
------------------------- ------------
cirrus cirrus-vga
vga VGA
qxl qxl-vga
virtio virtio-vga
come with a linear framebuffer (sometimes called "VGA compatibility
framebuffer"). This linear framebuffer lives in one of the PCI device's
MMIO BARs, and allows guest code (primarily: firmware drivers, and
non-accelerated OS drivers) to display graphics with direct memory access.
Due to architectural reasons on aarch64/KVM hosts, this kind of
framebuffer doesn't / can't work in
qemu-system-(arm|aarch64) -M virt
machines. Cache coherency issues guarantee a corrupted / unusable display.
The problem has been researched by several people, including kvm-arm
maintainers, and it's been decided that the best way (practically the only
way) to have boot time graphics for such guests is to consolidate on
QEMU's "virtio-gpu-pci" device.
>From <https://bugzilla.redhat.com/show_bug.cgi?id=1195176>, libvirt
supports
<devices>
<video>
<model type='virtio'/>
</video>
</devices>
but libvirt unconditionally maps @type='virtio' to QEMU's "virtio-vga"
device model. (See the qemuBuildDeviceVideoStr() function and the
"qemuDeviceVideo" enum impl.)
According to the above, this is not right for the "virt" machine type; the
qemu-system-(arm|aarch64) binaries don't even recognize the "virtio-vga"
device model (justifiedly). Whereas "virtio-gpu-pci", which is a pure
virtio device without a compatibility framebuffer, is available, and works
fine.
(The ArmVirtQemu ("AAVMF") platform of edk2 -- that is, the UEFI firmware
for "virt" -- supports "virtio-gpu-pci", as of upstream commit
3ef3209d3028. See
<https://tianocore.acgmultimedia.com/show_bug.cgi?id=66>.)
Override the default mapping of "virtio", from "virtio-vga" to
"virtio-gpu-pci", if qemuDomainMachineIsVirt() evaluates to true.
Cc: Andrea Bolognani <abologna(a)redhat.com>
Cc: Drew Jones <drjones(a)redhat.com>
Cc: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Cc: Martin Kletzander <mkletzan(a)redhat.com>
Suggested-by: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1372901
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
Acked-by: Martin Kletzander <mkletzan(a)redhat.com>
---
Notes:
v2:
- rewrap "qemuxml2argv-aarch64-video-virtio-gpu-pci.args" with
"test-wrap-argv.pl" [Martin]
- pick up Martin's ACK
src/qemu/qemu_command.c | 4 ++
tests/qemuxml2argvtest.c | 5 +++
tests/qemuxml2xmltest.c | 5 +++
tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args | 26 +++++++++++
tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml | 36 ++++++++++++++++
tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml | 45 ++++++++++++++++++++
6 files changed, 121 insertions(+)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863b9abb..038c38f2217c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4325,6 +4325,10 @@ qemuBuildDeviceVideoStr(const virDomainDef *def,
virDomainVideoTypeToString(video->type));
goto error;
}
+ if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO &&
+ qemuDomainMachineIsVirt(def)) {
+ model = "virtio-gpu-pci";
+ }
} else {
if (video->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index dbb0e4d56142..e8540779a4b5 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1872,6 +1872,11 @@ mymain(void)
QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM,
QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI);
+ DO_TEST("aarch64-video-virtio-gpu-pci",
+ QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+ QEMU_CAPS_DEVICE_VIRTIO_GPU, QEMU_CAPS_BOOTINDEX);
DO_TEST("aarch64-aavmf-virtio-mmio",
QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB,
QEMU_CAPS_DEVICE_VIRTIO_MMIO,
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 14c2b0ccf2ce..fb05c8571411 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -831,6 +831,11 @@ mymain(void)
QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM,
QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI);
+ DO_TEST("aarch64-video-virtio-gpu-pci",
+ QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+ QEMU_CAPS_DEVICE_VIRTIO_GPU, QEMU_CAPS_BOOTINDEX);
DO_TEST_FULL("aarch64-gic-none", WHEN_BOTH, GIC_NONE, NONE);
DO_TEST_FULL("aarch64-gic-none-v2", WHEN_BOTH, GIC_V2, NONE);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args
new file mode 100644
index 000000000000..76ee977a3ca2
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args
@@ -0,0 +1,26 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/opt/qemu-installed/bin/qemu-system-aarch64 \
+-name aarch64-vgpu \
+-S \
+-M virt \
+-cpu cortex-a57 \
+-m 1024 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid f3197c89-6457-44fe-b26d-897090ba6541 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-aarch64-vgpu/monitor.sock,server,nowait \
+-device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device ioh3420,port=0x9,chassis=2,id=pci.2,bus=pcie.0,multifunction=on,\
+addr=0x1.0x1 \
+-device virtio-net-pci,vlan=0,id=net0,mac=52:54:00:73:34:53,bus=pci.1,addr=0x0,\
+bootindex=1 \
+-net user,vlan=0,name=hostnet0 \
+-device virtio-gpu-pci,id=video0,bus=pci.2,addr=0x0
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml
new file mode 100644
index 000000000000..4b52a731b043
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+ <name>aarch64-vgpu</name>
+ <uuid>f3197c89-6457-44fe-b26d-897090ba6541</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <features>
+ <acpi/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>cortex-a57</model>
+ </cpu>
+ <devices>
+ <emulator>/opt/qemu-installed/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/>
+ </controller>
+ <interface type='user'>
+ <mac address='52:54:00:73:34:53'/>
+ <model type='virtio'/>
+ <boot order='1'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <video>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml
new file mode 100644
index 000000000000..26f6a51622ef
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml
@@ -0,0 +1,45 @@
+<domain type='qemu'>
+ <name>aarch64-vgpu</name>
+ <uuid>f3197c89-6457-44fe-b26d-897090ba6541</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <features>
+ <acpi/>
+ <gic version='2'/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>cortex-a57</model>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/opt/qemu-installed/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='ioh3420'/>
+ <target chassis='1' port='0x8'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='ioh3420'/>
+ <target chassis='2' port='0x9'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/>
+ </controller>
+ <interface type='user'>
+ <mac address='52:54:00:73:34:53'/>
+ <model type='virtio'/>
+ <boot order='1'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <video>
+ <model type='virtio' heads='1' primary='yes'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </video>
+ </devices>
+</domain>
--
2.9.2
4
12
[libvirt] [PATCH] test driver: File test_driver.c was splitted into smaller files.
by Tomáš Ryšavý 16 Sep '16
by Tomáš Ryšavý 16 Sep '16
16 Sep '16
Because the file had over 7000 lines. Now its splitted into 5
smaller files. It looks clearer and it's better for reading the code.
Signed-off-by: Tomáš Ryšavý <tom.rysavy.0(a)gmail.com>
---
po/POTFILES.in | 6 +-
src/Makefile.am | 8 +-
src/test/test_device_driver.c | 462 +++
src/test/test_device_driver.h | 1 +
src/test/test_driver.c | 6924 +------------------------------------
src/test/test_hypervisor_driver.c | 4152 ++++++++++++++++++++++
src/test/test_hypervisor_driver.h | 1 +
src/test/test_interface_driver.c | 487 +++
src/test/test_interface_driver.h | 1 +
src/test/test_network_driver.c | 540 +++
src/test/test_network_driver.h | 1 +
src/test/test_private_driver.h | 70 +
src/test/test_storage_driver.c | 1517 ++++++++
src/test/test_storage_driver.h | 1 +
14 files changed, 7259 insertions(+), 6912 deletions(-)
create mode 100644 src/test/test_device_driver.c
create mode 100644 src/test/test_device_driver.h
create mode 100644 src/test/test_hypervisor_driver.c
create mode 100644 src/test/test_hypervisor_driver.h
create mode 100644 src/test/test_interface_driver.c
create mode 100644 src/test/test_interface_driver.h
create mode 100644 src/test/test_network_driver.c
create mode 100644 src/test/test_network_driver.h
create mode 100644 src/test/test_private_driver.h
create mode 100644 src/test/test_storage_driver.c
create mode 100644 src/test/test_storage_driver.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 25dbc84..5738c4e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -173,7 +173,11 @@ src/storage/storage_backend_scsi.c
src/storage/storage_backend_sheepdog.c
src/storage/storage_backend_zfs.c
src/storage/storage_driver.c
-src/test/test_driver.c
+src/test/test_device_driver.c
+src/test/test_hypervisor_driver.c
+src/test/test_interface_driver.c
+src/test/test_network_driver.c
+src/test/test_storage_driver.c
src/uml/uml_conf.c
src/uml/uml_driver.c
src/util/iohelper.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8ee5567..4cf01fd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -689,7 +689,13 @@ check-local: check-protocol check-symfile check-symsorting \
# Mock driver, covering domains, storage, networks, etc
TEST_DRIVER_SOURCES = \
- test/test_driver.c test/test_driver.h
+ test/test_driver.c test/test_driver.h \
+ test/test_device_driver.c test/test_device_driver.h \
+ test/test_hypervisor_driver.c test/test_hypervisor_driver.h \
+ test/test_interface_driver.c test/test_interface_driver.h \
+ test/test_network_driver.c test/test_network_driver.h \
+ test/test_storage_driver.c test/test_storage_driver.h
+
# Now the Hypervisor specific drivers
XEN_DRIVER_SOURCES = \
diff --git a/src/test/test_device_driver.c b/src/test/test_device_driver.c
new file mode 100644
index 0000000..1172bc5
--- /dev/null
+++ b/src/test/test_device_driver.c
@@ -0,0 +1,462 @@
+/*
+ * test_device_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_device_driver.h"
+
+#include "test_private_driver.h"
+
+/* Node device implementations */
+
+static int
+testConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
+ virNodeDevicePtr dev,
+ int eventID,
+ virConnectNodeDeviceEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virNodeDeviceEventStateRegisterID(conn, driver->eventState,
+ dev, eventID, callback,
+ opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testNodeNumOfDevices(virConnectPtr conn,
+ const char *cap,
+ unsigned int flags)
+{
+ testDriverPtr driver = conn->privateData;
+ int ndevs = 0;
+ size_t i;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(driver);
+ for (i = 0; i < driver->devs.count; i++)
+ if ((cap == NULL) ||
+ virNodeDeviceHasCap(driver->devs.objs[i], cap))
+ ++ndevs;
+ testDriverUnlock(driver);
+
+ return ndevs;
+}
+
+static int
+testNodeListDevices(virConnectPtr conn,
+ const char *cap,
+ char **const names,
+ int maxnames,
+ unsigned int flags)
+{
+ testDriverPtr driver = conn->privateData;
+ int ndevs = 0;
+ size_t i;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(driver);
+ for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) {
+ virNodeDeviceObjLock(driver->devs.objs[i]);
+ if (cap == NULL ||
+ virNodeDeviceHasCap(driver->devs.objs[i], cap)) {
+ if (VIR_STRDUP(names[ndevs++], driver->devs.objs[i]->def->name) < 0) {
+ virNodeDeviceObjUnlock(driver->devs.objs[i]);
+ goto failure;
+ }
+ }
+ virNodeDeviceObjUnlock(driver->devs.objs[i]);
+ }
+ testDriverUnlock(driver);
+
+ return ndevs;
+
+ failure:
+ testDriverUnlock(driver);
+ --ndevs;
+ while (--ndevs >= 0)
+ VIR_FREE(names[ndevs]);
+ return -1;
+}
+
+static virNodeDevicePtr
+testNodeDeviceLookupByName(virConnectPtr conn, const char *name)
+{
+ testDriverPtr driver = conn->privateData;
+ virNodeDeviceObjPtr obj;
+ virNodeDevicePtr ret = NULL;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ name);
+ goto cleanup;
+ }
+
+ ret = virGetNodeDevice(conn, name);
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+static char *
+testNodeDeviceGetXMLDesc(virNodeDevicePtr dev,
+ unsigned int flags)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ ret = virNodeDeviceDefFormat(obj->def);
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+static char *
+testNodeDeviceGetParent(virNodeDevicePtr dev)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ char *ret = NULL;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ if (obj->def->parent) {
+ ignore_value(VIR_STRDUP(ret, obj->def->parent));
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no parent for this device"));
+ }
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+
+static int
+testNodeDeviceNumOfCaps(virNodeDevicePtr dev)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ virNodeDevCapsDefPtr caps;
+ int ncaps = 0;
+ int ret = -1;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ for (caps = obj->def->caps; caps; caps = caps->next)
+ ++ncaps;
+ ret = ncaps;
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ return ret;
+}
+
+
+static int
+testNodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
+{
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj;
+ virNodeDevCapsDefPtr caps;
+ int ncaps = 0;
+ int ret = -1;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto cleanup;
+ }
+
+ for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
+ if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0)
+ goto cleanup;
+ }
+ ret = ncaps;
+
+ cleanup:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ if (ret == -1) {
+ --ncaps;
+ while (--ncaps >= 0)
+ VIR_FREE(names[ncaps]);
+ }
+ return ret;
+}
+
+static virNodeDevicePtr
+testNodeDeviceCreateXML(virConnectPtr conn,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ testDriverPtr driver = conn->privateData;
+ virNodeDeviceDefPtr def = NULL;
+ virNodeDeviceObjPtr obj = NULL;
+ char *wwnn = NULL, *wwpn = NULL;
+ int parent_host = -1;
+ virNodeDevicePtr dev = NULL;
+ virNodeDevCapsDefPtr caps;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(driver);
+
+ def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL);
+ if (def == NULL)
+ goto cleanup;
+
+ /* We run these next two simply for validation */
+ if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
+ goto cleanup;
+
+ if (virNodeDeviceGetParentHost(&driver->devs,
+ def->name,
+ def->parent,
+ &parent_host) == -1) {
+ goto cleanup;
+ }
+
+ /* 'name' is supposed to be filled in by the node device backend, which
+ * we don't have. Use WWPN instead. */
+ VIR_FREE(def->name);
+ if (VIR_STRDUP(def->name, wwpn) < 0)
+ goto cleanup;
+
+ /* Fill in a random 'host' and 'unique_id' value,
+ * since this would also come from the backend */
+ caps = def->caps;
+ while (caps) {
+ if (caps->data.type != VIR_NODE_DEV_CAP_SCSI_HOST)
+ continue;
+
+ caps->data.scsi_host.host = virRandomBits(10);
+ caps->data.scsi_host.unique_id = 2;
+ caps = caps->next;
+ }
+
+
+ if (!(obj = virNodeDeviceAssignDef(&driver->devs, def)))
+ goto cleanup;
+ virNodeDeviceObjUnlock(obj);
+
+ event = virNodeDeviceEventLifecycleNew(def->name,
+ VIR_NODE_DEVICE_EVENT_CREATED,
+ 0);
+
+ dev = virGetNodeDevice(conn, def->name);
+ def = NULL;
+ cleanup:
+ testDriverUnlock(driver);
+ virNodeDeviceDefFree(def);
+ testObjectEventQueue(driver, event);
+ VIR_FREE(wwnn);
+ VIR_FREE(wwpn);
+ return dev;
+}
+
+static int
+testNodeDeviceDestroy(virNodeDevicePtr dev)
+{
+ int ret = 0;
+ testDriverPtr driver = dev->conn->privateData;
+ virNodeDeviceObjPtr obj = NULL;
+ char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
+ int parent_host = -1;
+ virObjectEventPtr event = NULL;
+
+ testDriverLock(driver);
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
+ testDriverUnlock(driver);
+
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NODE_DEVICE,
+ _("no node device with matching name '%s'"),
+ dev->name);
+ goto out;
+ }
+
+ if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1)
+ goto out;
+
+ if (VIR_STRDUP(parent_name, obj->def->parent) < 0)
+ goto out;
+
+ /* virNodeDeviceGetParentHost will cause the device object's lock to be
+ * taken, so we have to dup the parent's name and drop the lock
+ * before calling it. We don't need the reference to the object
+ * any more once we have the parent's name. */
+ virNodeDeviceObjUnlock(obj);
+
+ /* We do this just for basic validation */
+ if (virNodeDeviceGetParentHost(&driver->devs,
+ dev->name,
+ parent_name,
+ &parent_host) == -1) {
+ obj = NULL;
+ goto out;
+ }
+
+ event = virNodeDeviceEventLifecycleNew(dev->name,
+ VIR_NODE_DEVICE_EVENT_DELETED,
+ 0);
+
+ virNodeDeviceObjLock(obj);
+ virNodeDeviceObjRemove(&driver->devs, &obj);
+
+ out:
+ if (obj)
+ virNodeDeviceObjUnlock(obj);
+ testObjectEventQueue(driver, event);
+ VIR_FREE(parent_name);
+ VIR_FREE(wwnn);
+ VIR_FREE(wwpn);
+ return ret;
+}
+
+virNodeDeviceDriver testNodeDeviceDriver = {
+ .connectNodeDeviceEventRegisterAny = testConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
+ .connectNodeDeviceEventDeregisterAny = testConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
+ .nodeNumOfDevices = testNodeNumOfDevices, /* 0.7.2 */
+ .nodeListDevices = testNodeListDevices, /* 0.7.2 */
+ .nodeDeviceLookupByName = testNodeDeviceLookupByName, /* 0.7.2 */
+ .nodeDeviceGetXMLDesc = testNodeDeviceGetXMLDesc, /* 0.7.2 */
+ .nodeDeviceGetParent = testNodeDeviceGetParent, /* 0.7.2 */
+ .nodeDeviceNumOfCaps = testNodeDeviceNumOfCaps, /* 0.7.2 */
+ .nodeDeviceListCaps = testNodeDeviceListCaps, /* 0.7.2 */
+ .nodeDeviceCreateXML = testNodeDeviceCreateXML, /* 0.7.3 */
+ .nodeDeviceDestroy = testNodeDeviceDestroy, /* 0.7.3 */
+};
diff --git a/src/test/test_device_driver.h b/src/test/test_device_driver.h
new file mode 100644
index 0000000..b5bd2bd
--- /dev/null
+++ b/src/test/test_device_driver.h
@@ -0,0 +1 @@
+extern virNodeDeviceDriver testNodeDeviceDriver;
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 87799e1..c30ae29 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -65,113 +65,28 @@
#include "virdomainobjlist.h"
#include "virhostcpu.h"
-#define VIR_FROM_THIS VIR_FROM_TEST
+#include "test_hypervisor_driver.h"
+#include "test_storage_driver.h"
+#include "test_network_driver.h"
+#include "test_interface_driver.h"
+#include "test_device_driver.h"
-VIR_LOG_INIT("test.test_driver");
-
-
-#define MAX_CPUS 128
-
-struct _testCell {
- unsigned long mem;
- unsigned long freeMem;
- int numCpus;
- virCapsHostNUMACellCPU cpus[MAX_CPUS];
-};
-typedef struct _testCell testCell;
-typedef struct _testCell *testCellPtr;
-
-#define MAX_CELLS 128
-
-struct _testAuth {
- char *username;
- char *password;
-};
-typedef struct _testAuth testAuth;
-typedef struct _testAuth *testAuthPtr;
-
-struct _testDriver {
- virMutex lock;
-
- virNodeInfo nodeInfo;
- virInterfaceObjList ifaces;
- bool transaction_running;
- virInterfaceObjList backupIfaces;
- virStoragePoolObjList pools;
- virNodeDeviceObjList devs;
- int numCells;
- testCell cells[MAX_CELLS];
- size_t numAuths;
- testAuthPtr auths;
-
- /* virAtomic access only */
- volatile int nextDomID;
-
- /* immutable pointer, immutable object after being initialized with
- * testBuildCapabilities */
- virCapsPtr caps;
-
- /* immutable pointer, immutable object */
- virDomainXMLOptionPtr xmlopt;
-
- /* immutable pointer, self-locking APIs */
- virDomainObjListPtr domains;
- virNetworkObjListPtr networks;
- virObjectEventStatePtr eventState;
-};
-typedef struct _testDriver testDriver;
-typedef testDriver *testDriverPtr;
-
-static testDriverPtr defaultConn;
-static int defaultConnections;
-static virMutex defaultLock = VIR_MUTEX_INITIALIZER;
+#include "test_private_driver.h"
-#define TEST_MODEL "i686"
-#define TEST_EMULATOR "/usr/bin/test-hv"
-
-static const virNodeInfo defaultNodeInfo = {
- TEST_MODEL,
- 1024*1024*3, /* 3 GB */
- 16,
- 1400,
- 2,
- 2,
- 2,
- 2,
-};
-
-static void
-testDriverFree(testDriverPtr driver)
-{
- if (!driver)
- return;
-
- virObjectUnref(driver->caps);
- virObjectUnref(driver->xmlopt);
- virObjectUnref(driver->domains);
- virNodeDeviceObjListFree(&driver->devs);
- virObjectUnref(driver->networks);
- virInterfaceObjListFree(&driver->ifaces);
- virStoragePoolObjListFree(&driver->pools);
- virObjectEventStateFree(driver->eventState);
- virMutexUnlock(&driver->lock);
- virMutexDestroy(&driver->lock);
-
- VIR_FREE(driver);
-}
+VIR_LOG_INIT("test.test_driver");
-static void testDriverLock(testDriverPtr driver)
+void testDriverLock(testDriverPtr driver)
{
virMutexLock(&driver->lock);
}
-static void testDriverUnlock(testDriverPtr driver)
+void testDriverUnlock(testDriverPtr driver)
{
virMutexUnlock(&driver->lock);
}
-static void testObjectEventQueue(testDriverPtr driver,
+void testObjectEventQueue(testDriverPtr driver,
virObjectEventPtr event)
{
if (!event)
@@ -180,6825 +95,14 @@ static void testObjectEventQueue(testDriverPtr driver,
virObjectEventStateQueue(driver->eventState, event);
}
-#define TEST_NAMESPACE_HREF "http://libvirt.org/schemas/domain/test/1.0"
-
-typedef struct _testDomainNamespaceDef testDomainNamespaceDef;
-typedef testDomainNamespaceDef *testDomainNamespaceDefPtr;
-struct _testDomainNamespaceDef {
- int runstate;
- bool transient;
- bool hasManagedSave;
-
- unsigned int num_snap_nodes;
- xmlNodePtr *snap_nodes;
-};
-
-static void
-testDomainDefNamespaceFree(void *data)
-{
- testDomainNamespaceDefPtr nsdata = data;
- size_t i;
-
- if (!nsdata)
- return;
-
- for (i = 0; i < nsdata->num_snap_nodes; i++)
- xmlFreeNode(nsdata->snap_nodes[i]);
-
- VIR_FREE(nsdata->snap_nodes);
- VIR_FREE(nsdata);
-}
-
-static int
-testDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
- xmlNodePtr root ATTRIBUTE_UNUSED,
- xmlXPathContextPtr ctxt,
- void **data)
-{
- testDomainNamespaceDefPtr nsdata = NULL;
- xmlNodePtr *nodes = NULL;
- int tmp, n;
- size_t i;
- unsigned int tmpuint;
-
- if (xmlXPathRegisterNs(ctxt, BAD_CAST "test",
- BAD_CAST TEST_NAMESPACE_HREF) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Failed to register xml namespace '%s'"),
- TEST_NAMESPACE_HREF);
- return -1;
- }
-
- if (VIR_ALLOC(nsdata) < 0)
- return -1;
-
- n = virXPathNodeSet("./test:domainsnapshot", ctxt, &nodes);
- if (n < 0)
- goto error;
-
- if (n && VIR_ALLOC_N(nsdata->snap_nodes, n) < 0)
- goto error;
-
- for (i = 0; i < n; i++) {
- xmlNodePtr newnode = xmlCopyNode(nodes[i], 1);
- if (!newnode) {
- virReportOOMError();
- goto error;
- }
-
- nsdata->snap_nodes[nsdata->num_snap_nodes] = newnode;
- nsdata->num_snap_nodes++;
- }
- VIR_FREE(nodes);
-
- tmp = virXPathBoolean("boolean(./test:transient)", ctxt);
- if (tmp == -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid transient"));
- goto error;
- }
- nsdata->transient = tmp;
-
- tmp = virXPathBoolean("boolean(./test:hasmanagedsave)", ctxt);
- if (tmp == -1) {
- virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid hasmanagedsave"));
- goto error;
- }
- nsdata->hasManagedSave = tmp;
-
- tmp = virXPathUInt("string(./test:runstate)", ctxt, &tmpuint);
- if (tmp == 0) {
- if (tmpuint >= VIR_DOMAIN_LAST) {
- virReportError(VIR_ERR_XML_ERROR,
- _("runstate '%d' out of range'"), tmpuint);
- goto error;
- }
- nsdata->runstate = tmpuint;
- } else if (tmp == -1) {
- nsdata->runstate = VIR_DOMAIN_RUNNING;
- } else if (tmp == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid runstate"));
- goto error;
- }
-
- if (nsdata->transient && nsdata->runstate == VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("transient domain cannot have runstate 'shutoff'"));
- goto error;
- }
- if (nsdata->hasManagedSave && nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("domain with managedsave data can only have runstate 'shutoff'"));
- goto error;
- }
-
- *data = nsdata;
- return 0;
-
- error:
- VIR_FREE(nodes);
- testDomainDefNamespaceFree(nsdata);
- return -1;
-}
-
-static virCapsPtr
-testBuildCapabilities(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- virCapsPtr caps;
- virCapsGuestPtr guest;
- int guest_types[] = { VIR_DOMAIN_OSTYPE_HVM,
- VIR_DOMAIN_OSTYPE_XEN };
- size_t i, j;
-
- if ((caps = virCapabilitiesNew(VIR_ARCH_I686, false, false)) == NULL)
- goto error;
-
- if (virCapabilitiesAddHostFeature(caps, "pae") < 0)
- goto error;
- if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0)
- goto error;
-
- if (VIR_ALLOC_N(caps->host.pagesSize, 2) < 0)
- goto error;
-
- caps->host.pagesSize[caps->host.nPagesSize++] = 4;
- caps->host.pagesSize[caps->host.nPagesSize++] = 2048;
-
- for (i = 0; i < privconn->numCells; i++) {
- virCapsHostNUMACellCPUPtr cpu_cells;
- virCapsHostNUMACellPageInfoPtr pages;
- size_t nPages;
-
- if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0 ||
- VIR_ALLOC_N(pages, caps->host.nPagesSize) < 0) {
- VIR_FREE(cpu_cells);
- goto error;
- }
-
- nPages = caps->host.nPagesSize;
-
- memcpy(cpu_cells, privconn->cells[i].cpus,
- sizeof(*cpu_cells) * privconn->cells[i].numCpus);
-
- for (j = 0; j < nPages; j++)
- pages[j].size = caps->host.pagesSize[j];
-
- pages[0].avail = privconn->cells[i].mem / pages[0].size;
-
- if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].mem,
- privconn->cells[i].numCpus,
- cpu_cells, 0, NULL, nPages, pages) < 0)
- goto error;
- }
-
- for (i = 0; i < ARRAY_CARDINALITY(guest_types); i++) {
- if ((guest = virCapabilitiesAddGuest(caps,
- guest_types[i],
- VIR_ARCH_I686,
- TEST_EMULATOR,
- NULL,
- 0,
- NULL)) == NULL)
- goto error;
-
- if (virCapabilitiesAddGuestDomain(guest,
- VIR_DOMAIN_VIRT_TEST,
- NULL,
- NULL,
- 0,
- NULL) == NULL)
- goto error;
-
- if (virCapabilitiesAddGuestFeature(guest, "pae", true, true) == NULL)
- goto error;
- if (virCapabilitiesAddGuestFeature(guest, "nonpae", true, true) == NULL)
- goto error;
- }
-
- caps->host.nsecModels = 1;
- if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
- goto error;
- if (VIR_STRDUP(caps->host.secModels[0].model, "testSecurity") < 0)
- goto error;
-
- if (VIR_STRDUP(caps->host.secModels[0].doi, "") < 0)
- goto error;
-
- return caps;
-
- error:
- virObjectUnref(caps);
- return NULL;
-}
-
-
-static testDriverPtr
-testDriverNew(void)
-{
- virDomainXMLNamespace ns = {
- .parse = testDomainDefNamespaceParse,
- .free = testDomainDefNamespaceFree,
- };
- testDriverPtr ret;
-
- if (VIR_ALLOC(ret) < 0)
- return NULL;
-
- if (virMutexInit(&ret->lock) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot initialize mutex"));
- goto error;
- }
-
- if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) ||
- !(ret->eventState = virObjectEventStateNew()) ||
- !(ret->domains = virDomainObjListNew()) ||
- !(ret->networks = virNetworkObjListNew()))
- goto error;
-
- virAtomicIntSet(&ret->nextDomID, 1);
-
- return ret;
-
- error:
- testDriverFree(ret);
- return NULL;
-}
-
-
-static const char *defaultConnXML =
-"<node>"
-"<domain type='test'>"
-" <name>test</name>"
-" <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>"
-" <memory>8388608</memory>"
-" <currentMemory>2097152</currentMemory>"
-" <vcpu>2</vcpu>"
-" <os>"
-" <type>hvm</type>"
-" </os>"
-"</domain>"
-""
-"<network>"
-" <name>default</name>"
-" <uuid>dd8fe884-6c02-601e-7551-cca97df1c5df</uuid>"
-" <bridge name='virbr0'/>"
-" <forward/>"
-" <ip address='192.168.122.1' netmask='255.255.255.0'>"
-" <dhcp>"
-" <range start='192.168.122.2' end='192.168.122.254'/>"
-" </dhcp>"
-" </ip>"
-"</network>"
-""
-"<interface type=\"ethernet\" name=\"eth1\">"
-" <start mode=\"onboot\"/>"
-" <mac address=\"aa:bb:cc:dd:ee:ff\"/>"
-" <mtu size=\"1492\"/>"
-" <protocol family=\"ipv4\">"
-" <ip address=\"192.168.0.5\" prefix=\"24\"/>"
-" <route gateway=\"192.168.0.1\"/>"
-" </protocol>"
-"</interface>"
-""
-"<pool type='dir'>"
-" <name>default-pool</name>"
-" <uuid>dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566</uuid>"
-" <target>"
-" <path>/default-pool</path>"
-" </target>"
-"</pool>"
-""
-"<device>"
-" <name>computer</name>"
-" <capability type='system'>"
-" <hardware>"
-" <vendor>Libvirt</vendor>"
-" <version>Test driver</version>"
-" <serial>123456</serial>"
-" <uuid>11111111-2222-3333-4444-555555555555</uuid>"
-" </hardware>"
-" <firmware>"
-" <vendor>Libvirt</vendor>"
-" <version>Test Driver</version>"
-" <release_date>01/22/2007</release_date>"
-" </firmware>"
-" </capability>"
-"</device>"
-"<device>"
-" <name>test-scsi-host-vport</name>"
-" <parent>computer</parent>"
-" <capability type='scsi_host'>"
-" <host>1</host>"
-" <capability type='fc_host'>"
-" <wwnn>2000000012341234</wwnn>"
-" <wwpn>1000000012341234</wwpn>"
-" </capability>"
-" <capability type='vport_ops'/>"
-" </capability>"
-"</device>"
-"</node>";
-
-
-static const char *defaultPoolSourcesLogicalXML =
-"<sources>\n"
-" <source>\n"
-" <device path='/dev/sda20'/>\n"
-" <name>testvg1</name>\n"
-" <format type='lvm2'/>\n"
-" </source>\n"
-" <source>\n"
-" <device path='/dev/sda21'/>\n"
-" <name>testvg2</name>\n"
-" <format type='lvm2'/>\n"
-" </source>\n"
-"</sources>\n";
-
-static const char *defaultPoolSourcesNetFSXML =
-"<sources>\n"
-" <source>\n"
-" <host name='%s'/>\n"
-" <dir path='/testshare'/>\n"
-" <format type='nfs'/>\n"
-" </source>\n"
-"</sources>\n";
-
-static const unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull);
-static const unsigned long long defaultPoolAlloc;
-
-static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
-static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
-
-static virDomainObjPtr
-testDomObjFromDomain(virDomainPtr domain)
-{
- virDomainObjPtr vm;
- testDriverPtr driver = domain->conn->privateData;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
-
- vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
- if (!vm) {
- virUUIDFormat(domain->uuid, uuidstr);
- virReportError(VIR_ERR_NO_DOMAIN,
- _("no domain with matching uuid '%s' (%s)"),
- uuidstr, domain->name);
- }
-
- return vm;
-}
-
-static char *
-testDomainGenerateIfname(virDomainDefPtr domdef)
-{
- int maxif = 1024;
- int ifctr;
- size_t i;
-
- for (ifctr = 0; ifctr < maxif; ++ifctr) {
- char *ifname;
- int found = 0;
-
- if (virAsprintf(&ifname, "testnet%d", ifctr) < 0)
- return NULL;
-
- /* Generate network interface names */
- for (i = 0; i < domdef->nnets; i++) {
- if (domdef->nets[i]->ifname &&
- STREQ(domdef->nets[i]->ifname, ifname)) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- return ifname;
- VIR_FREE(ifname);
- }
-
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Exceeded max iface limit %d"), maxif);
- return NULL;
-}
-
-static int
-testDomainGenerateIfnames(virDomainDefPtr domdef)
-{
- size_t i = 0;
-
- for (i = 0; i < domdef->nnets; i++) {
- char *ifname;
- if (domdef->nets[i]->ifname)
- continue;
-
- ifname = testDomainGenerateIfname(domdef);
- if (!ifname)
- return -1;
-
- domdef->nets[i]->ifname = ifname;
- }
-
- return 0;
-}
-
-
-static void
-testDomainShutdownState(virDomainPtr domain,
- virDomainObjPtr privdom,
- virDomainShutoffReason reason)
-{
- virDomainObjRemoveTransientDef(privdom);
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
-
- if (domain)
- domain->id = -1;
-}
-
-/* Set up domain runtime state */
-static int
-testDomainStartState(testDriverPtr privconn,
- virDomainObjPtr dom,
- virDomainRunningReason reason)
-{
- int ret = -1;
-
- virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
- dom->def->id = virAtomicIntAdd(&privconn->nextDomID, 1);
-
- if (virDomainObjSetDefTransient(privconn->caps,
- privconn->xmlopt,
- dom) < 0) {
- goto cleanup;
- }
-
- dom->hasManagedSave = false;
- ret = 0;
- cleanup:
- if (ret < 0)
- testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
- return ret;
-}
-
-
-static char *testBuildFilename(const char *relativeTo,
- const char *filename)
-{
- char *offset;
- int baseLen;
- char *ret;
-
- if (!filename || filename[0] == '\0')
- return NULL;
- if (filename[0] == '/') {
- ignore_value(VIR_STRDUP(ret, filename));
- return ret;
- }
-
- offset = strrchr(relativeTo, '/');
- if ((baseLen = (offset-relativeTo+1))) {
- char *absFile;
- int totalLen = baseLen + strlen(filename) + 1;
- if (VIR_ALLOC_N(absFile, totalLen) < 0)
- return NULL;
- if (virStrncpy(absFile, relativeTo, baseLen, totalLen) == NULL) {
- VIR_FREE(absFile);
- return NULL;
- }
- strcat(absFile, filename);
- return absFile;
- } else {
- ignore_value(VIR_STRDUP(ret, filename));
- return ret;
- }
-}
-
-static xmlNodePtr
-testParseXMLDocFromFile(xmlNodePtr node, const char *file, const char *type)
-{
- xmlNodePtr ret = NULL;
- xmlDocPtr doc = NULL;
- char *absFile = NULL;
- char *relFile = virXMLPropString(node, "file");
-
- if (relFile != NULL) {
- absFile = testBuildFilename(file, relFile);
- VIR_FREE(relFile);
- if (!absFile) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("resolving %s filename"), type);
- return NULL;
- }
-
- if (!(doc = virXMLParse(absFile, NULL, type)))
- goto error;
-
- ret = xmlCopyNode(xmlDocGetRootElement(doc), 1);
- if (!ret) {
- virReportOOMError();
- goto error;
- }
- xmlReplaceNode(node, ret);
- xmlFreeNode(node);
- } else {
- ret = node;
- }
-
- error:
- xmlFreeDoc(doc);
- VIR_FREE(absFile);
- return ret;
-}
-
-static int
-testParseNodeInfo(virNodeInfoPtr nodeInfo, xmlXPathContextPtr ctxt)
-{
- char *str;
- long l;
- int ret;
-
- ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->nodes = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu nodes value"));
- goto error;
- }
-
- ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->sockets = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu sockets value"));
- goto error;
- }
-
- ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->cores = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu cores value"));
- goto error;
- }
-
- ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->threads = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu threads value"));
- goto error;
- }
-
- nodeInfo->cpus = (nodeInfo->cores * nodeInfo->threads *
- nodeInfo->sockets * nodeInfo->nodes);
- ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
- if (ret == 0) {
- if (l < nodeInfo->cpus)
- nodeInfo->cpus = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu active value"));
- goto error;
- }
- ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->mhz = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node cpu mhz value"));
- goto error;
- }
-
- str = virXPathString("string(/node/cpu/model[1])", ctxt);
- if (str != NULL) {
- if (virStrcpyStatic(nodeInfo->model, str) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Model %s too big for destination"), str);
- VIR_FREE(str);
- goto error;
- }
- VIR_FREE(str);
- }
-
- ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
- if (ret == 0) {
- nodeInfo->memory = l;
- } else if (ret == -2) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("invalid node memory value"));
- goto error;
- }
-
- return 0;
- error:
- return -1;
-}
-
-static int
-testParseDomainSnapshots(testDriverPtr privconn,
- virDomainObjPtr domobj,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- size_t i;
- int ret = -1;
- testDomainNamespaceDefPtr nsdata = domobj->def->namespaceData;
- xmlNodePtr *nodes = nsdata->snap_nodes;
-
- for (i = 0; i < nsdata->num_snap_nodes; i++) {
- virDomainSnapshotObjPtr snap;
- virDomainSnapshotDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "domainsnapshot");
- if (!node)
- goto error;
-
- def = virDomainSnapshotDefParseNode(ctxt->doc, node,
- privconn->caps,
- privconn->xmlopt,
- VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
- VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL |
- VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
- if (!def)
- goto error;
-
- if (!(snap = virDomainSnapshotAssignDef(domobj->snapshots, def))) {
- virDomainSnapshotDefFree(def);
- goto error;
- }
-
- if (def->current) {
- if (domobj->current_snapshot) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("more than one snapshot claims to be active"));
- goto error;
- }
-
- domobj->current_snapshot = snap;
- }
- }
-
- if (virDomainSnapshotUpdateRelations(domobj->snapshots) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Snapshots have inconsistent relations for "
- "domain %s"), domobj->def->name);
- goto error;
- }
-
- ret = 0;
- error:
- return ret;
-}
-
-static int
-testParseDomains(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virDomainObjPtr obj;
-
- num = virXPathNodeSet("/node/domain", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virDomainDefPtr def;
- testDomainNamespaceDefPtr nsdata;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "domain");
- if (!node)
- goto error;
-
- def = virDomainDefParseNode(ctxt->doc, node,
- privconn->caps, privconn->xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE);
- if (!def)
- goto error;
-
- if (testDomainGenerateIfnames(def) < 0 ||
- !(obj = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- 0, NULL))) {
- virDomainDefFree(def);
- goto error;
- }
-
- if (testParseDomainSnapshots(privconn, obj, file, ctxt) < 0) {
- virObjectUnlock(obj);
- goto error;
- }
-
- nsdata = def->namespaceData;
- obj->persistent = !nsdata->transient;
- obj->hasManagedSave = nsdata->hasManagedSave;
-
- if (nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
- if (testDomainStartState(privconn, obj,
- VIR_DOMAIN_RUNNING_BOOTED) < 0) {
- virObjectUnlock(obj);
- goto error;
- }
- } else {
- testDomainShutdownState(NULL, obj, 0);
- }
- virDomainObjSetState(obj, nsdata->runstate, 0);
-
- virObjectUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseNetworks(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virNetworkObjPtr obj;
-
- num = virXPathNodeSet("/node/network", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virNetworkDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "network");
- if (!node)
- goto error;
-
- def = virNetworkDefParseNode(ctxt->doc, node);
- if (!def)
- goto error;
-
- if (!(obj = virNetworkAssignDef(privconn->networks, def, 0))) {
- virNetworkDefFree(def);
- goto error;
- }
-
- obj->active = 1;
- virNetworkObjEndAPI(&obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseInterfaces(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virInterfaceObjPtr obj;
-
- num = virXPathNodeSet("/node/interface", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virInterfaceDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "interface");
- if (!node)
- goto error;
-
- def = virInterfaceDefParseNode(ctxt->doc, node);
- if (!def)
- goto error;
-
- if (!(obj = virInterfaceAssignDef(&privconn->ifaces, def))) {
- virInterfaceDefFree(def);
- goto error;
- }
-
- obj->active = 1;
- virInterfaceObjUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testOpenVolumesForPool(const char *file,
- xmlXPathContextPtr ctxt,
- virStoragePoolObjPtr pool,
- int poolidx)
-{
- char *vol_xpath;
- size_t i;
- int num, ret = -1;
- xmlNodePtr *nodes = NULL;
- virStorageVolDefPtr def = NULL;
-
- /* Find storage volumes */
- if (virAsprintf(&vol_xpath, "/node/pool[%d]/volume", poolidx) < 0)
- goto error;
-
- num = virXPathNodeSet(vol_xpath, ctxt, &nodes);
- VIR_FREE(vol_xpath);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "volume");
- if (!node)
- goto error;
-
- def = virStorageVolDefParseNode(pool->def, ctxt->doc, node, 0);
- if (!def)
- goto error;
-
- if (def->target.path == NULL) {
- if (virAsprintf(&def->target.path, "%s/%s",
- pool->def->target.path,
- def->name) == -1)
- goto error;
- }
-
- if (!def->key && VIR_STRDUP(def->key, def->target.path) < 0)
- goto error;
- if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, def) < 0)
- goto error;
-
- pool->def->allocation += def->target.allocation;
- pool->def->available = (pool->def->capacity -
- pool->def->allocation);
- def = NULL;
- }
-
- ret = 0;
- error:
- virStorageVolDefFree(def);
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseStorage(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virStoragePoolObjPtr obj;
-
- num = virXPathNodeSet("/node/pool", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virStoragePoolDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "pool");
- if (!node)
- goto error;
-
- def = virStoragePoolDefParseNode(ctxt->doc, node);
- if (!def)
- goto error;
-
- if (!(obj = virStoragePoolObjAssignDef(&privconn->pools,
- def))) {
- virStoragePoolDefFree(def);
- goto error;
- }
-
- if (testStoragePoolObjSetDefaults(obj) == -1) {
- virStoragePoolObjUnlock(obj);
- goto error;
- }
- obj->active = 1;
-
- /* Find storage volumes */
- if (testOpenVolumesForPool(file, ctxt, obj, i+1) < 0) {
- virStoragePoolObjUnlock(obj);
- goto error;
- }
-
- virStoragePoolObjUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseNodedevs(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
- virNodeDeviceObjPtr obj;
-
- num = virXPathNodeSet("/node/device", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- virNodeDeviceDefPtr def;
- xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
- "nodedev");
- if (!node)
- goto error;
-
- def = virNodeDeviceDefParseNode(ctxt->doc, node, 0, NULL);
- if (!def)
- goto error;
-
- if (!(obj = virNodeDeviceAssignDef(&privconn->devs, def))) {
- virNodeDeviceDefFree(def);
- goto error;
- }
-
- virNodeDeviceObjUnlock(obj);
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testParseAuthUsers(testDriverPtr privconn,
- xmlXPathContextPtr ctxt)
-{
- int num, ret = -1;
- size_t i;
- xmlNodePtr *nodes = NULL;
-
- num = virXPathNodeSet("/node/auth/user", ctxt, &nodes);
- if (num < 0)
- goto error;
-
- privconn->numAuths = num;
- if (num && VIR_ALLOC_N(privconn->auths, num) < 0)
- goto error;
-
- for (i = 0; i < num; i++) {
- char *username, *password;
-
- ctxt->node = nodes[i];
- username = virXPathString("string(.)", ctxt);
- if (!username || STREQ(username, "")) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("missing username in /node/auth/user field"));
- VIR_FREE(username);
- goto error;
- }
- /* This field is optional. */
- password = virXMLPropString(nodes[i], "password");
-
- privconn->auths[i].username = username;
- privconn->auths[i].password = password;
- }
-
- ret = 0;
- error:
- VIR_FREE(nodes);
- return ret;
-}
-
-static int
-testOpenParse(testDriverPtr privconn,
- const char *file,
- xmlXPathContextPtr ctxt)
-{
- if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Root element is not 'node'"));
- goto error;
- }
-
- if (testParseNodeInfo(&privconn->nodeInfo, ctxt) < 0)
- goto error;
- if (testParseDomains(privconn, file, ctxt) < 0)
- goto error;
- if (testParseNetworks(privconn, file, ctxt) < 0)
- goto error;
- if (testParseInterfaces(privconn, file, ctxt) < 0)
- goto error;
- if (testParseStorage(privconn, file, ctxt) < 0)
- goto error;
- if (testParseNodedevs(privconn, file, ctxt) < 0)
- goto error;
- if (testParseAuthUsers(privconn, ctxt) < 0)
- goto error;
+unsigned long long defaultPoolCap = (100 * 1024 * 1024 * 1024ull);
+unsigned long long defaultPoolAlloc;
- return 0;
- error:
- return -1;
-}
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
+int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
/* No shared state between simultaneous test connections initialized
* from a file. */
-static int
-testOpenFromFile(virConnectPtr conn, const char *file)
-{
- xmlDocPtr doc = NULL;
- xmlXPathContextPtr ctxt = NULL;
- testDriverPtr privconn;
-
- if (!(privconn = testDriverNew()))
- return VIR_DRV_OPEN_ERROR;
-
- testDriverLock(privconn);
- conn->privateData = privconn;
-
- if (!(privconn->caps = testBuildCapabilities(conn)))
- goto error;
-
- if (!(doc = virXMLParseFileCtxt(file, &ctxt)))
- goto error;
-
- privconn->numCells = 0;
- memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
-
- if (testOpenParse(privconn, file, ctxt) < 0)
- goto error;
-
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- testDriverUnlock(privconn);
-
- return 0;
-
- error:
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- testDriverFree(privconn);
- conn->privateData = NULL;
- return VIR_DRV_OPEN_ERROR;
-}
-
-/* Simultaneous test:///default connections should share the same
- * common state (among other things, this allows testing event
- * detection in one connection for an action caused in another). */
-static int
-testOpenDefault(virConnectPtr conn)
-{
- int u;
- testDriverPtr privconn = NULL;
- xmlDocPtr doc = NULL;
- xmlXPathContextPtr ctxt = NULL;
-
- virMutexLock(&defaultLock);
- if (defaultConnections++) {
- conn->privateData = defaultConn;
- virMutexUnlock(&defaultLock);
- return VIR_DRV_OPEN_SUCCESS;
- }
-
- if (!(privconn = testDriverNew()))
- goto error;
-
- conn->privateData = privconn;
-
- memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
-
- /* Numa setup */
- privconn->numCells = 2;
- for (u = 0; u < privconn->numCells; ++u) {
- privconn->cells[u].numCpus = 8;
- privconn->cells[u].mem = (u + 1) * 2048 * 1024;
- privconn->cells[u].freeMem = (u + 1) * 1024 * 1024;
- }
- for (u = 0; u < 16; u++) {
- virBitmapPtr siblings = virBitmapNew(16);
- if (!siblings)
- goto error;
- ignore_value(virBitmapSetBit(siblings, u));
- privconn->cells[u / 8].cpus[(u % 8)].id = u;
- privconn->cells[u / 8].cpus[(u % 8)].socket_id = u / 8;
- privconn->cells[u / 8].cpus[(u % 8)].core_id = u % 8;
- privconn->cells[u / 8].cpus[(u % 8)].siblings = siblings;
- }
-
- if (!(privconn->caps = testBuildCapabilities(conn)))
- goto error;
-
- if (!(doc = virXMLParseStringCtxt(defaultConnXML,
- _("(test driver)"), &ctxt)))
- goto error;
-
- if (testOpenParse(privconn, NULL, ctxt) < 0)
- goto error;
-
- defaultConn = privconn;
-
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- virMutexUnlock(&defaultLock);
-
- return VIR_DRV_OPEN_SUCCESS;
-
- error:
- testDriverFree(privconn);
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc(doc);
- conn->privateData = NULL;
- defaultConnections--;
- virMutexUnlock(&defaultLock);
- return VIR_DRV_OPEN_ERROR;
-}
-
-static int
-testConnectAuthenticate(virConnectPtr conn,
- virConnectAuthPtr auth)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
- ssize_t i;
- char *username = NULL, *password = NULL;
-
- if (privconn->numAuths == 0)
- return 0;
-
- /* Authentication is required because the test XML contains a
- * non-empty <auth/> section. First we must ask for a username.
- */
- username = virAuthGetUsername(conn, auth, "test", NULL, "localhost"/*?*/);
- if (!username) {
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed when asking for username"));
- goto cleanup;
- }
-
- /* Does the username exist? */
- for (i = 0; i < privconn->numAuths; ++i) {
- if (STREQ(privconn->auths[i].username, username))
- goto found_user;
- }
- i = -1;
-
- found_user:
- /* Even if we didn't find the user, we still ask for a password. */
- if (i == -1 || privconn->auths[i].password != NULL) {
- password = virAuthGetPassword(conn, auth, "test",
- username, "localhost");
- if (password == NULL) {
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed when asking for password"));
- goto cleanup;
- }
- }
-
- if (i == -1 ||
- (password && STRNEQ(privconn->auths[i].password, password))) {
- virReportError(VIR_ERR_AUTH_FAILED, "%s",
- _("authentication failed, see test XML for the correct username/password"));
- goto cleanup;
- }
-
- ret = 0;
- cleanup:
- VIR_FREE(username);
- VIR_FREE(password);
- return ret;
-}
-
-static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
- virConnectAuthPtr auth,
- virConfPtr conf ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- int ret;
-
- virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
-
- if (!conn->uri)
- return VIR_DRV_OPEN_DECLINED;
-
- if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test"))
- return VIR_DRV_OPEN_DECLINED;
-
- /* Remote driver should handle these. */
- if (conn->uri->server)
- return VIR_DRV_OPEN_DECLINED;
-
- /* From this point on, the connection is for us. */
- if (!conn->uri->path
- || conn->uri->path[0] == '\0'
- || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("testOpen: supply a path or use test:///default"));
- return VIR_DRV_OPEN_ERROR;
- }
-
- if (STREQ(conn->uri->path, "/default"))
- ret = testOpenDefault(conn);
- else
- ret = testOpenFromFile(conn,
- conn->uri->path);
-
- if (ret != VIR_DRV_OPEN_SUCCESS)
- return ret;
-
- /* Fake authentication. */
- if (testConnectAuthenticate(conn, auth) < 0)
- return VIR_DRV_OPEN_ERROR;
-
- return VIR_DRV_OPEN_SUCCESS;
-}
-
-static int testConnectClose(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- bool dflt = false;
-
- if (privconn == defaultConn) {
- dflt = true;
- virMutexLock(&defaultLock);
- if (--defaultConnections) {
- virMutexUnlock(&defaultLock);
- return 0;
- }
- }
-
- testDriverLock(privconn);
- testDriverFree(privconn);
-
- if (dflt) {
- defaultConn = NULL;
- virMutexUnlock(&defaultLock);
- }
-
- conn->privateData = NULL;
- return 0;
-}
-
-static int testConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned long *hvVer)
-{
- *hvVer = 2;
- return 0;
-}
-
-static char *testConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return virGetHostname();
-}
-
-
-static int testConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-static int testConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-static int testConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-static int testConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *type ATTRIBUTE_UNUSED)
-{
- return 32;
-}
-
-static char *
-testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char **xmlCPUs,
- unsigned int ncpus,
- unsigned int flags)
-{
- char *cpu;
-
- virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
-
- cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
-
- return cpu;
-}
-
-static int testNodeGetInfo(virConnectPtr conn,
- virNodeInfoPtr info)
-{
- testDriverPtr privconn = conn->privateData;
- testDriverLock(privconn);
- memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo));
- testDriverUnlock(privconn);
- return 0;
-}
-
-static char *testConnectGetCapabilities(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- char *xml;
- testDriverLock(privconn);
- xml = virCapabilitiesFormatXML(privconn->caps);
- testDriverUnlock(privconn);
- return xml;
-}
-
-static char *
-testConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- char *ret;
- const char *sysinfo = "<sysinfo type='smbios'>\n"
- " <bios>\n"
- " <entry name='vendor'>LENOVO</entry>\n"
- " <entry name='version'>G4ETA1WW (2.61 )</entry>\n"
- " <entry name='date'>05/07/2014</entry>\n"
- " <entry name='release'>2.61</entry>\n"
- " </bios>\n"
- "</sysinfo>\n";
-
- virCheckFlags(0, NULL);
-
- ignore_value(VIR_STRDUP(ret, sysinfo));
- return ret;
-}
-
-static const char *
-testConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return "TEST";
-}
-
-static int testConnectNumOfDomains(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int count;
-
- testDriverLock(privconn);
- count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL);
- testDriverUnlock(privconn);
-
- return count;
-}
-
-static int testDomainIsActive(virDomainPtr dom)
-{
- virDomainObjPtr obj;
- int ret;
-
- if (!(obj = testDomObjFromDomain(dom)))
- return -1;
-
- ret = virDomainObjIsActive(obj);
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-static int testDomainIsPersistent(virDomainPtr dom)
-{
- virDomainObjPtr obj;
- int ret;
-
- if (!(obj = testDomObjFromDomain(dom)))
- return -1;
-
- ret = obj->persistent;
-
- virDomainObjEndAPI(&obj);
- return ret;
-}
-
-static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-static virDomainPtr
-testDomainCreateXML(virConnectPtr conn, const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainDefPtr def;
- virDomainObjPtr dom = NULL;
- virObjectEventPtr event = NULL;
- unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
- virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
-
- if (flags & VIR_DOMAIN_START_VALIDATE)
- parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
- testDriverLock(privconn);
- if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
- parse_flags)) == NULL)
- goto cleanup;
-
- if (testDomainGenerateIfnames(def) < 0)
- goto cleanup;
- if (!(dom = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
- VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
- NULL)))
- goto cleanup;
- def = NULL;
-
- if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
- if (!dom->persistent) {
- virDomainObjListRemove(privconn->domains, dom);
- dom = NULL;
- }
- goto cleanup;
- }
-
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- if (dom)
- virObjectUnlock(dom);
- testObjectEventQueue(privconn, event);
- virDomainDefFree(def);
- testDriverUnlock(privconn);
- return ret;
-}
-
-
-static virDomainPtr testDomainLookupByID(virConnectPtr conn,
- int id)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainObjPtr dom;
-
- if (!(dom = virDomainObjListFindByID(privconn->domains, id))) {
- virReportError(VIR_ERR_NO_DOMAIN, NULL);
- goto cleanup;
- }
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- if (dom)
- virObjectUnlock(dom);
- return ret;
-}
-
-static virDomainPtr testDomainLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainObjPtr dom;
-
- if (!(dom = virDomainObjListFindByUUID(privconn->domains, uuid))) {
- virReportError(VIR_ERR_NO_DOMAIN, NULL);
- goto cleanup;
- }
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- if (dom)
- virObjectUnlock(dom);
- return ret;
-}
-
-static virDomainPtr testDomainLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainObjPtr dom;
-
- if (!(dom = virDomainObjListFindByName(privconn->domains, name))) {
- virReportError(VIR_ERR_NO_DOMAIN, NULL);
- goto cleanup;
- }
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- virDomainObjEndAPI(&dom);
- return ret;
-}
-
-static int testConnectListDomains(virConnectPtr conn,
- int *ids,
- int maxids)
-{
- testDriverPtr privconn = conn->privateData;
-
- return virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
- NULL, NULL);
-}
-
-static int testDomainDestroy(virDomainPtr domain)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainResume(virDomainPtr domain)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
- domain->name);
- goto cleanup;
- }
-
- virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_UNPAUSED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_RESUMED,
- VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainSuspend(virDomainPtr domain)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
- int state;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- state = virDomainObjGetState(privdom, NULL);
- if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
- virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
- domain->name);
- goto cleanup;
- }
-
- virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainShutdownFlags(virDomainPtr domain,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("domain '%s' not running"), domain->name);
- goto cleanup;
- }
-
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainShutdown(virDomainPtr domain)
-{
- return testDomainShutdownFlags(domain, 0);
-}
-
-/* Similar behaviour as shutdown */
-static int testDomainReboot(virDomainPtr domain,
- unsigned int action ATTRIBUTE_UNUSED)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
- VIR_DOMAIN_SHUTDOWN_USER);
-
- switch (privdom->def->onReboot) {
- case VIR_DOMAIN_LIFECYCLE_DESTROY:
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
- VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- break;
-
- case VIR_DOMAIN_LIFECYCLE_RESTART:
- virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_BOOTED);
- break;
-
- case VIR_DOMAIN_LIFECYCLE_PRESERVE:
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
- VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- break;
-
- case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
- virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
- VIR_DOMAIN_RUNNING_BOOTED);
- break;
-
- default:
- virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
- VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- break;
- }
-
- if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
- }
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainGetInfo(virDomainPtr domain,
- virDomainInfoPtr info)
-{
- struct timeval tv;
- virDomainObjPtr privdom;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("getting time of day"));
- goto cleanup;
- }
-
- info->state = virDomainObjGetState(privdom, NULL);
- info->memory = privdom->def->mem.cur_balloon;
- info->maxMem = virDomainDefGetMemoryTotal(privdom->def);
- info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
- info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll));
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetState(virDomainPtr domain,
- int *state,
- int *reason,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
-
- virCheckFlags(0, -1);
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- *state = virDomainObjGetState(privdom, reason);
-
- virDomainObjEndAPI(&privdom);
-
- return 0;
-}
-
-#define TEST_SAVE_MAGIC "TestGuestMagic"
-
-static int
-testDomainSaveFlags(virDomainPtr domain, const char *path,
- const char *dxml, unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- char *xml = NULL;
- int fd = -1;
- int len;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
- if (dxml) {
- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
- _("xml modification unsupported"));
- return -1;
- }
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- xml = virDomainDefFormat(privdom->def, privconn->caps,
- VIR_DOMAIN_DEF_FORMAT_SECURE);
-
- if (xml == NULL) {
- virReportSystemError(errno,
- _("saving domain '%s' failed to allocate space for metadata"),
- domain->name);
- goto cleanup;
- }
-
- if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': open failed"),
- domain->name, path);
- goto cleanup;
- }
- len = strlen(xml);
- if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
- if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
- if (safewrite(fd, xml, len) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
-
- if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno,
- _("saving domain '%s' to '%s': write failed"),
- domain->name, path);
- goto cleanup;
- }
- fd = -1;
-
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SAVED);
-
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
- cleanup:
- VIR_FREE(xml);
-
- /* Don't report failure in close or unlink, because
- * in either case we're already in a failure scenario
- * and have reported a earlier error */
- if (ret != 0) {
- VIR_FORCE_CLOSE(fd);
- unlink(path);
- }
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int
-testDomainSave(virDomainPtr domain,
- const char *path)
-{
- return testDomainSaveFlags(domain, path, NULL, 0);
-}
-
-static int
-testDomainRestoreFlags(virConnectPtr conn,
- const char *path,
- const char *dxml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- char *xml = NULL;
- char magic[15];
- int fd = -1;
- int len;
- virDomainDefPtr def = NULL;
- virDomainObjPtr dom = NULL;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
- if (dxml) {
- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
- _("xml modification unsupported"));
- return -1;
- }
-
- if ((fd = open(path, O_RDONLY)) < 0) {
- virReportSystemError(errno,
- _("cannot read domain image '%s'"),
- path);
- goto cleanup;
- }
- if (saferead(fd, magic, sizeof(magic)) != sizeof(magic)) {
- virReportSystemError(errno,
- _("incomplete save header in '%s'"),
- path);
- goto cleanup;
- }
- if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("mismatched header magic"));
- goto cleanup;
- }
- if (saferead(fd, (char*)&len, sizeof(len)) != sizeof(len)) {
- virReportSystemError(errno,
- _("failed to read metadata length in '%s'"),
- path);
- goto cleanup;
- }
- if (len < 1 || len > 8192) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("length of metadata out of range"));
- goto cleanup;
- }
- if (VIR_ALLOC_N(xml, len+1) < 0)
- goto cleanup;
- if (saferead(fd, xml, len) != len) {
- virReportSystemError(errno,
- _("incomplete metadata in '%s'"), path);
- goto cleanup;
- }
- xml[len] = '\0';
-
- def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
- VIR_DOMAIN_DEF_PARSE_INACTIVE);
- if (!def)
- goto cleanup;
-
- if (testDomainGenerateIfnames(def) < 0)
- goto cleanup;
- if (!(dom = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
- VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
- NULL)))
- goto cleanup;
- def = NULL;
-
- if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0) {
- if (!dom->persistent) {
- virDomainObjListRemove(privconn->domains, dom);
- dom = NULL;
- }
- goto cleanup;
- }
-
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_RESTORED);
- ret = 0;
-
- cleanup:
- virDomainDefFree(def);
- VIR_FREE(xml);
- VIR_FORCE_CLOSE(fd);
- if (dom)
- virObjectUnlock(dom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int
-testDomainRestore(virConnectPtr conn,
- const char *path)
-{
- return testDomainRestoreFlags(conn, path, NULL, 0);
-}
-
-static int testDomainCoreDumpWithFormat(virDomainPtr domain,
- const char *to,
- unsigned int dumpformat,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- int fd = -1;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DUMP_CRASH, -1);
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
- virReportSystemError(errno,
- _("domain '%s' coredump: failed to open %s"),
- domain->name, to);
- goto cleanup;
- }
- if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
- virReportSystemError(errno,
- _("domain '%s' coredump: failed to write header to %s"),
- domain->name, to);
- goto cleanup;
- }
- if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno,
- _("domain '%s' coredump: write failed: %s"),
- domain->name, to);
- goto cleanup;
- }
-
- /* we don't support non-raw formats in test driver */
- if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
- virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
- _("kdump-compressed format is not supported here"));
- goto cleanup;
- }
-
- if (flags & VIR_DUMP_CRASH) {
- testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_CRASHED);
- if (!privdom->persistent)
- virDomainObjListRemove(privconn->domains, privdom);
- }
-
- ret = 0;
- cleanup:
- VIR_FORCE_CLOSE(fd);
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-
-static int
-testDomainCoreDump(virDomainPtr domain,
- const char *to,
- unsigned int flags)
-{
- return testDomainCoreDumpWithFormat(domain, to,
- VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags);
-}
-
-
-static char *
-testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
-{
- char *ret;
-
- ignore_value(VIR_STRDUP(ret, "linux"));
- return ret;
-}
-
-
-static unsigned long long
-testDomainGetMaxMemory(virDomainPtr domain)
-{
- virDomainObjPtr privdom;
- unsigned long long ret = 0;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return 0;
-
- ret = virDomainDefGetMemoryTotal(privdom->def);
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainSetMaxMemory(virDomainPtr domain,
- unsigned long memory)
-{
- virDomainObjPtr privdom;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- /* XXX validate not over host memory wrt to other domains */
- virDomainDefSetMemoryTotal(privdom->def, memory);
-
- virDomainObjEndAPI(&privdom);
- return 0;
-}
-
-static int testDomainSetMemory(virDomainPtr domain,
- unsigned long memory)
-{
- virDomainObjPtr privdom;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (memory > virDomainDefGetMemoryTotal(privdom->def)) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privdom->def->mem.cur_balloon = memory;
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainDefPtr def;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG |
- VIR_DOMAIN_VCPU_MAXIMUM, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- if (!(def = virDomainObjGetOneDef(vm, flags)))
- goto cleanup;
-
- if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
- ret = virDomainDefGetVcpusMax(def);
- else
- ret = virDomainDefGetVcpus(def);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainGetMaxVcpus(virDomainPtr domain)
-{
- return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_VCPU_MAXIMUM));
-}
-
-static int
-testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
- unsigned int flags)
-{
- testDriverPtr driver = domain->conn->privateData;
- virDomainObjPtr privdom = NULL;
- virDomainDefPtr def;
- virDomainDefPtr persistentDef;
- int ret = -1, maxvcpus;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG |
- VIR_DOMAIN_VCPU_MAXIMUM, -1);
-
- if ((maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < 0)
- return -1;
-
- if (nrCpus > maxvcpus) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested cpu amount exceeds maximum supported amount "
- "(%d > %d)"), nrCpus, maxvcpus);
- return -1;
- }
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
- goto cleanup;
-
- if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested cpu amount exceeds maximum (%d > %d)"),
- nrCpus, virDomainDefGetVcpusMax(def));
- goto cleanup;
- }
-
- if (persistentDef &&
- !(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
- virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested cpu amount exceeds maximum (%d > %d)"),
- nrCpus, virDomainDefGetVcpusMax(persistentDef));
- goto cleanup;
- }
-
- if (def &&
- virDomainDefSetVcpus(def, nrCpus) < 0)
- goto cleanup;
-
- if (persistentDef) {
- if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
- if (virDomainDefSetVcpusMax(persistentDef, nrCpus,
- driver->xmlopt) < 0)
- goto cleanup;
- } else {
- if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
- goto cleanup;
- }
- }
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainSetVcpus(virDomainPtr domain, unsigned int nrCpus)
-{
- return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_AFFECT_LIVE);
-}
-
-static int testDomainGetVcpus(virDomainPtr domain,
- virVcpuInfoPtr info,
- int maxinfo,
- unsigned char *cpumaps,
- int maplen)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virDomainDefPtr def;
- size_t i;
- int maxcpu, hostcpus;
- int ret = -1;
- struct timeval tv;
- unsigned long long statbase;
- virBitmapPtr allcpumap = NULL;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (!virDomainObjIsActive(privdom)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot list vcpus for an inactive domain"));
- goto cleanup;
- }
-
- def = privdom->def;
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportSystemError(errno,
- "%s", _("getting time of day"));
- goto cleanup;
- }
-
- statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
-
- hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo);
- maxcpu = maplen * 8;
- if (maxcpu > hostcpus)
- maxcpu = hostcpus;
-
- if (!(allcpumap = virBitmapNew(hostcpus)))
- goto cleanup;
-
- virBitmapSetAll(allcpumap);
-
- /* Clamp to actual number of vcpus */
- if (maxinfo > virDomainDefGetVcpus(privdom->def))
- maxinfo = virDomainDefGetVcpus(privdom->def);
-
- memset(info, 0, sizeof(*info) * maxinfo);
- memset(cpumaps, 0, maxinfo * maplen);
-
- for (i = 0; i < maxinfo; i++) {
- virDomainVcpuDefPtr vcpu = virDomainDefGetVcpu(def, i);
- virBitmapPtr bitmap = NULL;
-
- if (!vcpu->online)
- continue;
-
- if (vcpu->cpumask)
- bitmap = vcpu->cpumask;
- else if (def->cpumask)
- bitmap = def->cpumask;
- else
- bitmap = allcpumap;
-
- if (cpumaps)
- virBitmapToDataBuf(bitmap, VIR_GET_CPUMAP(cpumaps, maplen, i), maplen);
-
- info[i].number = i;
- info[i].state = VIR_VCPU_RUNNING;
- info[i].cpu = virBitmapLastSetBit(bitmap);
-
- /* Fake an increasing cpu time value */
- info[i].cpuTime = statbase / 10;
- }
-
- ret = maxinfo;
- cleanup:
- virBitmapFree(allcpumap);
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainPinVcpu(virDomainPtr domain,
- unsigned int vcpu,
- unsigned char *cpumap,
- int maplen)
-{
- virDomainVcpuDefPtr vcpuinfo;
- virDomainObjPtr privdom;
- virDomainDefPtr def;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- def = privdom->def;
-
- if (!virDomainObjIsActive(privdom)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot pin vcpus on an inactive domain"));
- goto cleanup;
- }
-
- if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu)) ||
- !vcpuinfo->online) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("requested vcpu '%d' is not present in the domain"),
- vcpu);
- goto cleanup;
- }
-
- virBitmapFree(vcpuinfo->cpumask);
-
- if (!(vcpuinfo->cpumask = virBitmapNewData(cpumap, maplen)))
- goto cleanup;
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetVcpuPinInfo(virDomainPtr dom,
- int ncpumaps,
- unsigned char *cpumaps,
- int maplen,
- unsigned int flags)
-{
- testDriverPtr driver = dom->conn->privateData;
- virDomainObjPtr privdom;
- virDomainDefPtr def;
- int ret = -1;
-
- if (!(privdom = testDomObjFromDomain(dom)))
- return -1;
-
- if (!(def = virDomainObjGetOneDef(privdom, flags)))
- goto cleanup;
-
- ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps,
- VIR_NODEINFO_MAXCPUS(driver->nodeInfo),
- NULL);
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainDefPtr def;
- virDomainObjPtr privdom;
- char *ret = NULL;
-
- /* Flags checked by virDomainDefFormat */
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return NULL;
-
- def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
- privdom->newDef ? privdom->newDef : privdom->def;
-
- ret = virDomainDefFormat(def, privconn->caps,
- virDomainDefFormatConvertXMLFlags(flags));
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testConnectNumOfDefinedDomains(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
-
- return virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL);
-}
-
-static int testConnectListDefinedDomains(virConnectPtr conn,
- char **const names,
- int maxnames)
-{
-
- testDriverPtr privconn = conn->privateData;
-
- memset(names, 0, sizeof(*names)*maxnames);
- return virDomainObjListGetInactiveNames(privconn->domains, names, maxnames,
- NULL, NULL);
-}
-
-static virDomainPtr testDomainDefineXMLFlags(virConnectPtr conn,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virDomainPtr ret = NULL;
- virDomainDefPtr def;
- virDomainObjPtr dom = NULL;
- virObjectEventPtr event = NULL;
- virDomainDefPtr oldDef = NULL;
- unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
-
- virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
-
- if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
- parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
-
- if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
- parse_flags)) == NULL)
- goto cleanup;
-
- if (testDomainGenerateIfnames(def) < 0)
- goto cleanup;
- if (!(dom = virDomainObjListAdd(privconn->domains,
- def,
- privconn->xmlopt,
- 0,
- &oldDef)))
- goto cleanup;
- def = NULL;
- dom->persistent = 1;
-
- event = virDomainEventLifecycleNewFromObj(dom,
- VIR_DOMAIN_EVENT_DEFINED,
- !oldDef ?
- VIR_DOMAIN_EVENT_DEFINED_ADDED :
- VIR_DOMAIN_EVENT_DEFINED_UPDATED);
-
- ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
- if (ret)
- ret->id = dom->def->id;
-
- cleanup:
- virDomainDefFree(def);
- virDomainDefFree(oldDef);
- if (dom)
- virObjectUnlock(dom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static virDomainPtr
-testDomainDefineXML(virConnectPtr conn, const char *xml)
-{
- return testDomainDefineXMLFlags(conn, xml, 0);
-}
-
-static char *testDomainGetMetadata(virDomainPtr dom,
- int type,
- const char *uri,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
- char *ret;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG, NULL);
-
- if (!(privdom = testDomObjFromDomain(dom)))
- return NULL;
-
- ret = virDomainObjGetMetadata(privdom, type, uri, flags);
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainSetMetadata(virDomainPtr dom,
- int type,
- const char *metadata,
- const char *key,
- const char *uri,
- unsigned int flags)
-{
- testDriverPtr privconn = dom->conn->privateData;
- virDomainObjPtr privdom;
- int ret;
-
- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
- VIR_DOMAIN_AFFECT_CONFIG, -1);
-
- if (!(privdom = testDomObjFromDomain(dom)))
- return -1;
-
- ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
- privconn->caps, privconn->xmlopt,
- NULL, NULL, flags);
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-
-static int testNodeGetCellsFreeMemory(virConnectPtr conn,
- unsigned long long *freemems,
- int startCell, int maxCells)
-{
- testDriverPtr privconn = conn->privateData;
- int cell;
- size_t i;
- int ret = -1;
-
- testDriverLock(privconn);
- if (startCell > privconn->numCells) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("Range exceeds available cells"));
- goto cleanup;
- }
-
- for (cell = startCell, i = 0;
- (cell < privconn->numCells && i < maxCells);
- ++cell, ++i) {
- freemems[i] = privconn->cells[cell].mem;
- }
- ret = i;
-
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-#define TEST_NB_CPU_STATS 4
-
-static int
-testNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
- int cpuNum ATTRIBUTE_UNUSED,
- virNodeCPUStatsPtr params,
- int *nparams,
- unsigned int flags)
-{
- size_t i = 0;
-
- virCheckFlags(0, -1);
-
- if (params == NULL) {
- *nparams = TEST_NB_CPU_STATS;
- return 0;
- }
-
- for (i = 0; i < *nparams && i < 4; i++) {
- switch (i) {
- case 0:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_USER, 9797400000) < 0)
- return -1;
- break;
- case 1:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_KERNEL, 34678723400000) < 0)
- return -1;
- break;
- case 2:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_IDLE, 87264900000) < 0)
- return -1;
- break;
- case 3:
- if (virHostCPUStatsAssign(¶ms[i],
- VIR_NODE_CPU_STATS_IOWAIT, 763600000) < 0)
- return -1;
- break;
- }
- }
-
- *nparams = i;
- return 0;
-}
-
-static unsigned long long
-testNodeGetFreeMemory(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- unsigned int freeMem = 0;
- size_t i;
-
- testDriverLock(privconn);
-
- for (i = 0; i < privconn->numCells; i++)
- freeMem += privconn->cells[i].freeMem;
-
- testDriverUnlock(privconn);
- return freeMem;
-}
-
-static int
-testNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned int npages,
- unsigned int *pages ATTRIBUTE_UNUSED,
- int startCell ATTRIBUTE_UNUSED,
- unsigned int cellCount,
- unsigned long long *counts,
- unsigned int flags)
-{
- size_t i = 0, j = 0;
- int x = 6;
-
- virCheckFlags(0, -1);
-
- for (i = 0; i < cellCount; i++) {
- for (j = 0; j < npages; j++) {
- x = x * 2 + 7;
- counts[(i * npages) + j] = x;
- }
- }
-
- return 0;
-}
-
-static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Domain '%s' is already running"), domain->name);
- goto cleanup;
- }
-
- if (testDomainStartState(privconn, privdom,
- VIR_DOMAIN_RUNNING_BOOTED) < 0)
- goto cleanup;
- domain->id = privdom->def->id;
-
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testDomainCreate(virDomainPtr domain)
-{
- return testDomainCreateWithFlags(domain, 0);
-}
-
-static int testDomainUndefineFlags(virDomainPtr domain,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr privdom;
- virObjectEventPtr event = NULL;
- int nsnapshots;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
- VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
-
-
- if (!(privdom = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (privdom->hasManagedSave &&
- !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("Refusing to undefine while domain managed "
- "save image exists"));
- goto cleanup;
- }
-
- /* Requiring an inactive VM is part of the documented API for
- * UNDEFINE_SNAPSHOTS_METADATA
- */
- if (!virDomainObjIsActive(privdom) &&
- (nsnapshots = virDomainSnapshotObjListNum(privdom->snapshots,
- NULL, 0))) {
- if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("cannot delete inactive domain with %d "
- "snapshots"),
- nsnapshots);
- goto cleanup;
- }
-
- /* There isn't actually anything to do, we are just emulating qemu
- * behavior here. */
- }
-
- event = virDomainEventLifecycleNewFromObj(privdom,
- VIR_DOMAIN_EVENT_UNDEFINED,
- VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
- privdom->hasManagedSave = false;
-
- if (virDomainObjIsActive(privdom))
- privdom->persistent = 0;
- else
- virDomainObjListRemove(privconn->domains, privdom);
-
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- testObjectEventQueue(privconn, event);
- return ret;
-}
-
-static int testDomainUndefine(virDomainPtr domain)
-{
- return testDomainUndefineFlags(domain, 0);
-}
-
-static int testDomainGetAutostart(virDomainPtr domain,
- int *autostart)
-{
- virDomainObjPtr privdom;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- *autostart = privdom->autostart;
-
- virDomainObjEndAPI(&privdom);
- return 0;
-}
-
-
-static int testDomainSetAutostart(virDomainPtr domain,
- int autostart)
-{
- virDomainObjPtr privdom;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- privdom->autostart = autostart ? 1 : 0;
-
- virDomainObjEndAPI(&privdom);
- return 0;
-}
-
-static char *testDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
- int *nparams)
-{
- char *type = NULL;
-
- if (nparams)
- *nparams = 1;
-
- ignore_value(VIR_STRDUP(type, "fair"));
-
- return type;
-}
-
-static int
-testDomainGetSchedulerParametersFlags(virDomainPtr domain,
- virTypedParameterPtr params,
- int *nparams,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- if (virTypedParameterAssign(params, VIR_DOMAIN_SCHEDULER_WEIGHT,
- VIR_TYPED_PARAM_UINT, 50) < 0)
- goto cleanup;
- /* XXX */
- /*params[0].value.ui = privdom->weight;*/
-
- *nparams = 1;
- ret = 0;
-
- cleanup:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainGetSchedulerParameters(virDomainPtr domain,
- virTypedParameterPtr params,
- int *nparams)
-{
- return testDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
-}
-
-static int
-testDomainSetSchedulerParametersFlags(virDomainPtr domain,
- virTypedParameterPtr params,
- int nparams,
- unsigned int flags)
-{
- virDomainObjPtr privdom;
- int ret = -1;
- size_t i;
-
- virCheckFlags(0, -1);
- if (virTypedParamsValidate(params, nparams,
- VIR_DOMAIN_SCHEDULER_WEIGHT,
- VIR_TYPED_PARAM_UINT,
- NULL) < 0)
- return -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- for (i = 0; i < nparams; i++) {
- if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
- /* XXX */
- /*privdom->weight = params[i].value.ui;*/
- }
- }
-
- ret = 0;
-
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int
-testDomainSetSchedulerParameters(virDomainPtr domain,
- virTypedParameterPtr params,
- int nparams)
-{
- return testDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
-}
-
-static int testDomainBlockStats(virDomainPtr domain,
- const char *path,
- virDomainBlockStatsPtr stats)
-{
- virDomainObjPtr privdom;
- struct timeval tv;
- unsigned long long statbase;
- int ret = -1;
-
- if (!*path) {
- virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
- _("summary statistics are not supported yet"));
- return ret;
- }
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return ret;
-
- if (virDomainDiskIndexByName(privdom->def, path, false) < 0) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("invalid path: %s"), path);
- goto error;
- }
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportSystemError(errno,
- "%s", _("getting time of day"));
- goto error;
- }
-
- /* No significance to these numbers, just enough to mix it up*/
- statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
- stats->rd_req = statbase / 10;
- stats->rd_bytes = statbase / 20;
- stats->wr_req = statbase / 30;
- stats->wr_bytes = statbase / 40;
- stats->errs = tv.tv_sec / 2;
-
- ret = 0;
- error:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-static int testDomainInterfaceStats(virDomainPtr domain,
- const char *path,
- virDomainInterfaceStatsPtr stats)
-{
- virDomainObjPtr privdom;
- struct timeval tv;
- unsigned long long statbase;
- size_t i;
- int found = 0, ret = -1;
-
- if (!(privdom = testDomObjFromDomain(domain)))
- return -1;
-
- for (i = 0; i < privdom->def->nnets; i++) {
- if (privdom->def->nets[i]->ifname &&
- STREQ(privdom->def->nets[i]->ifname, path)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("invalid path, '%s' is not a known interface"), path);
- goto error;
- }
-
- if (gettimeofday(&tv, NULL) < 0) {
- virReportSystemError(errno,
- "%s", _("getting time of day"));
- goto error;
- }
-
- /* No significance to these numbers, just enough to mix it up*/
- statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
- stats->rx_bytes = statbase / 10;
- stats->rx_packets = statbase / 100;
- stats->rx_errs = tv.tv_sec / 1;
- stats->rx_drop = tv.tv_sec / 2;
- stats->tx_bytes = statbase / 20;
- stats->tx_packets = statbase / 110;
- stats->tx_errs = tv.tv_sec / 3;
- stats->tx_drop = tv.tv_sec / 4;
-
- ret = 0;
- error:
- virDomainObjEndAPI(&privdom);
- return ret;
-}
-
-
-static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkObjPtr net;
- virNetworkPtr ret = NULL;
-
- net = virNetworkObjFindByUUID(privconn->networks, uuid);
- if (net == NULL) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-static virNetworkPtr testNetworkLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkObjPtr net;
- virNetworkPtr ret = NULL;
-
- net = virNetworkObjFindByName(privconn->networks, name);
- if (net == NULL) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-
-static int testConnectNumOfNetworks(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numActive;
-
- numActive = virNetworkObjListNumOfNetworks(privconn->networks,
- true, NULL, conn);
- return numActive;
-}
-
-static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
- testDriverPtr privconn = conn->privateData;
- int n;
-
- n = virNetworkObjListGetNames(privconn->networks,
- true, names, nnames, NULL, conn);
- return n;
-}
-
-static int testConnectNumOfDefinedNetworks(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numInactive;
-
- numInactive = virNetworkObjListNumOfNetworks(privconn->networks,
- false, NULL, conn);
- return numInactive;
-}
-
-static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
- testDriverPtr privconn = conn->privateData;
- int n;
-
- n = virNetworkObjListGetNames(privconn->networks,
- false, names, nnames, NULL, conn);
- return n;
-}
-
-static int
-testConnectListAllNetworks(virConnectPtr conn,
- virNetworkPtr **nets,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
-
- virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
-
- return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags);
-}
-
-static int testNetworkIsActive(virNetworkPtr net)
-{
- testDriverPtr privconn = net->conn->privateData;
- virNetworkObjPtr obj;
- int ret = -1;
-
- obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
- if (!obj) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
- ret = virNetworkObjIsActive(obj);
-
- cleanup:
- virNetworkObjEndAPI(&obj);
- return ret;
-}
-
-static int testNetworkIsPersistent(virNetworkPtr net)
-{
- testDriverPtr privconn = net->conn->privateData;
- virNetworkObjPtr obj;
- int ret = -1;
-
- obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
- if (!obj) {
- virReportError(VIR_ERR_NO_NETWORK, NULL);
- goto cleanup;
- }
- ret = obj->persistent;
-
- cleanup:
- virNetworkObjEndAPI(&obj);
- return ret;
-}
-
-
-static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkDefPtr def;
- virNetworkObjPtr net = NULL;
- virNetworkPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- if ((def = virNetworkDefParseString(xml)) == NULL)
- goto cleanup;
-
- if (!(net = virNetworkAssignDef(privconn->networks, def,
- VIR_NETWORK_OBJ_LIST_ADD_LIVE |
- VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
- goto cleanup;
- def = NULL;
- net->active = 1;
-
- event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
- VIR_NETWORK_EVENT_STARTED,
- 0);
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkDefFree(def);
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-static
-virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml)
-{
- testDriverPtr privconn = conn->privateData;
- virNetworkDefPtr def;
- virNetworkObjPtr net = NULL;
- virNetworkPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- if ((def = virNetworkDefParseString(xml)) == NULL)
- goto cleanup;
-
- if (!(net = virNetworkAssignDef(privconn->networks, def, 0)))
- goto cleanup;
- def = NULL;
-
- event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
- VIR_NETWORK_EVENT_DEFINED,
- 0);
-
- ret = virGetNetwork(conn, net->def->name, net->def->uuid);
-
- cleanup:
- virNetworkDefFree(def);
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&net);
- return ret;
-}
-
-static int testNetworkUndefine(virNetworkPtr network)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
-
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virNetworkObjIsActive(privnet)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("Network '%s' is still running"), network->name);
- goto cleanup;
- }
-
- event = virNetworkEventLifecycleNew(network->name, network->uuid,
- VIR_NETWORK_EVENT_UNDEFINED,
- 0);
-
- virNetworkRemoveInactive(privconn->networks, privnet);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static int
-testNetworkUpdate(virNetworkPtr net,
- unsigned int command,
- unsigned int section,
- int parentIndex,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = net->conn->privateData;
- virNetworkObjPtr network = NULL;
- int isActive, ret = -1;
-
- virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
- VIR_NETWORK_UPDATE_AFFECT_CONFIG,
- -1);
-
- network = virNetworkObjFindByUUID(privconn->networks, net->uuid);
- if (!network) {
- virReportError(VIR_ERR_NO_NETWORK,
- "%s", _("no network with matching uuid"));
- goto cleanup;
- }
-
- /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
- * is active, else change CONFIG
- */
- isActive = virNetworkObjIsActive(network);
- if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE
- | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
- VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
- if (isActive)
- flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
- else
- flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
- }
-
- /* update the network config in memory/on disk */
- if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
- goto cleanup;
-
- ret = 0;
- cleanup:
- virNetworkObjEndAPI(&network);
- return ret;
-}
-
-static int testNetworkCreate(virNetworkPtr network)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virNetworkObjIsActive(privnet)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("Network '%s' is already running"), network->name);
- goto cleanup;
- }
-
- privnet->active = 1;
- event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
- VIR_NETWORK_EVENT_STARTED,
- 0);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static int testNetworkDestroy(virNetworkPtr network)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privnet->active = 0;
- event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
- VIR_NETWORK_EVENT_STOPPED,
- 0);
- if (!privnet->persistent)
- virNetworkRemoveInactive(privconn->networks, privnet);
-
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static char *testNetworkGetXMLDesc(virNetworkPtr network,
- unsigned int flags)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- ret = virNetworkDefFormat(privnet->def, flags);
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static char *testNetworkGetBridgeName(virNetworkPtr network) {
- testDriverPtr privconn = network->conn->privateData;
- char *bridge = NULL;
- virNetworkObjPtr privnet;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!(privnet->def->bridge)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("network '%s' does not have a bridge name."),
- privnet->def->name);
- goto cleanup;
- }
-
- ignore_value(VIR_STRDUP(bridge, privnet->def->bridge));
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return bridge;
-}
-
-static int testNetworkGetAutostart(virNetworkPtr network,
- int *autostart)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- *autostart = privnet->autostart;
- ret = 0;
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-static int testNetworkSetAutostart(virNetworkPtr network,
- int autostart)
-{
- testDriverPtr privconn = network->conn->privateData;
- virNetworkObjPtr privnet;
- int ret = -1;
-
- privnet = virNetworkObjFindByName(privconn->networks, network->name);
- if (privnet == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privnet->autostart = autostart ? 1 : 0;
- ret = 0;
-
- cleanup:
- virNetworkObjEndAPI(&privnet);
- return ret;
-}
-
-
-/*
- * Physical host interface routines
- */
-
-
-static int testConnectNumOfInterfaces(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- int count = 0;
-
- testDriverLock(privconn);
- for (i = 0; (i < privconn->ifaces.count); i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (virInterfaceObjIsActive(privconn->ifaces.objs[i]))
- count++;
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
- return count;
-}
-
-static int testConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
- if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- goto error;
- }
- }
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static int testConnectNumOfDefinedInterfaces(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- int count = 0;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->ifaces.count; i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (!virInterfaceObjIsActive(privconn->ifaces.objs[i]))
- count++;
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
- return count;
-}
-
-static int testConnectListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
- virInterfaceObjLock(privconn->ifaces.objs[i]);
- if (!virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
- if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- goto error;
- }
- }
- virInterfaceObjUnlock(privconn->ifaces.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static virInterfacePtr testInterfaceLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virInterfaceObjPtr iface;
- virInterfacePtr ret = NULL;
-
- testDriverLock(privconn);
- iface = virInterfaceFindByName(&privconn->ifaces, name);
- testDriverUnlock(privconn);
-
- if (iface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
- if (iface)
- virInterfaceObjUnlock(iface);
- return ret;
-}
-
-static virInterfacePtr testInterfaceLookupByMACString(virConnectPtr conn,
- const char *mac)
-{
- testDriverPtr privconn = conn->privateData;
- virInterfaceObjPtr iface;
- int ifacect;
- virInterfacePtr ret = NULL;
-
- testDriverLock(privconn);
- ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1);
- testDriverUnlock(privconn);
-
- if (ifacect == 0) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- if (ifacect > 1) {
- virReportError(VIR_ERR_MULTIPLE_INTERFACES, NULL);
- goto cleanup;
- }
-
- ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
- if (iface)
- virInterfaceObjUnlock(iface);
- return ret;
-}
-
-static int testInterfaceIsActive(virInterfacePtr iface)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr obj;
- int ret = -1;
-
- testDriverLock(privconn);
- obj = virInterfaceFindByName(&privconn->ifaces, iface->name);
- testDriverUnlock(privconn);
- if (!obj) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
- ret = virInterfaceObjIsActive(obj);
-
- cleanup:
- if (obj)
- virInterfaceObjUnlock(obj);
- return ret;
-}
-
-static int testInterfaceChangeBegin(virConnectPtr conn,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- if (privconn->transaction_running) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("there is another transaction running."));
- goto cleanup;
- }
-
- privconn->transaction_running = true;
-
- if (virInterfaceObjListClone(&privconn->ifaces,
- &privconn->backupIfaces) < 0)
- goto cleanup;
-
- ret = 0;
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceChangeCommit(virConnectPtr conn,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
-
- if (!privconn->transaction_running) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("no transaction running, "
- "nothing to be committed."));
- goto cleanup;
- }
-
- virInterfaceObjListFree(&privconn->backupIfaces);
- privconn->transaction_running = false;
-
- ret = 0;
-
- cleanup:
- testDriverUnlock(privconn);
-
- return ret;
-}
-
-static int testInterfaceChangeRollback(virConnectPtr conn,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
-
- if (!privconn->transaction_running) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("no transaction running, "
- "nothing to rollback."));
- goto cleanup;
- }
-
- virInterfaceObjListFree(&privconn->ifaces);
- privconn->ifaces.count = privconn->backupIfaces.count;
- privconn->ifaces.objs = privconn->backupIfaces.objs;
- privconn->backupIfaces.count = 0;
- privconn->backupIfaces.objs = NULL;
-
- privconn->transaction_running = false;
-
- ret = 0;
-
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
- unsigned int flags)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
- testDriverUnlock(privconn);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, __FUNCTION__);
- goto cleanup;
- }
-
- ret = virInterfaceDefFormat(privinterface->def);
-
- cleanup:
- if (privinterface)
- virInterfaceObjUnlock(privinterface);
- return ret;
-}
-
-
-static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virInterfaceDefPtr def;
- virInterfaceObjPtr iface = NULL;
- virInterfacePtr ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- if ((def = virInterfaceDefParseString(xmlStr)) == NULL)
- goto cleanup;
-
- if ((iface = virInterfaceAssignDef(&privconn->ifaces, def)) == NULL)
- goto cleanup;
- def = NULL;
-
- ret = virGetInterface(conn, iface->def->name, iface->def->mac);
-
- cleanup:
- virInterfaceDefFree(def);
- if (iface)
- virInterfaceObjUnlock(iface);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceUndefine(virInterfacePtr iface)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- int ret = -1;
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- virInterfaceRemove(&privconn->ifaces,
- privinterface);
- ret = 0;
-
- cleanup:
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceCreate(virInterfacePtr iface,
- unsigned int flags)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- if (privinterface->active != 0) {
- virReportError(VIR_ERR_OPERATION_INVALID, NULL);
- goto cleanup;
- }
-
- privinterface->active = 1;
- ret = 0;
-
- cleanup:
- if (privinterface)
- virInterfaceObjUnlock(privinterface);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int testInterfaceDestroy(virInterfacePtr iface,
- unsigned int flags)
-{
- testDriverPtr privconn = iface->conn->privateData;
- virInterfaceObjPtr privinterface;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privinterface = virInterfaceFindByName(&privconn->ifaces,
- iface->name);
-
- if (privinterface == NULL) {
- virReportError(VIR_ERR_NO_INTERFACE, NULL);
- goto cleanup;
- }
-
- if (privinterface->active == 0) {
- virReportError(VIR_ERR_OPERATION_INVALID, NULL);
- goto cleanup;
- }
-
- privinterface->active = 0;
- ret = 0;
-
- cleanup:
- if (privinterface)
- virInterfaceObjUnlock(privinterface);
- testDriverUnlock(privconn);
- return ret;
-}
-
-
-
-/*
- * Storage Driver routines
- */
-
-
-static int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool)
-{
-
- pool->def->capacity = defaultPoolCap;
- pool->def->allocation = defaultPoolAlloc;
- pool->def->available = defaultPoolCap - defaultPoolAlloc;
-
- return VIR_STRDUP(pool->configFile, "");
-}
-
-
-static virStoragePoolPtr
-testStoragePoolLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolObjPtr pool;
- virStoragePoolPtr ret = NULL;
-
- testDriverLock(privconn);
- pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
- testDriverUnlock(privconn);
-
- if (pool == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- if (pool)
- virStoragePoolObjUnlock(pool);
- return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolLookupByName(virConnectPtr conn,
- const char *name)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolObjPtr pool;
- virStoragePoolPtr ret = NULL;
-
- testDriverLock(privconn);
- pool = virStoragePoolObjFindByName(&privconn->pools, name);
- testDriverUnlock(privconn);
-
- if (pool == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- if (pool)
- virStoragePoolObjUnlock(pool);
- return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolLookupByVolume(virStorageVolPtr vol)
-{
- return testStoragePoolLookupByName(vol->conn, vol->pool);
-}
-
-static int
-testConnectNumOfStoragePools(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numActive = 0;
- size_t i;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++)
- if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
- numActive++;
- testDriverUnlock(privconn);
-
- return numActive;
-}
-
-static int
-testConnectListStoragePools(virConnectPtr conn,
- char **const names,
- int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; i < privconn->pools.count && n < nnames; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
- VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- goto error;
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static int
-testConnectNumOfDefinedStoragePools(virConnectPtr conn)
-{
- testDriverPtr privconn = conn->privateData;
- int numInactive = 0;
- size_t i;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
- numInactive++;
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return numInactive;
-}
-
-static int
-testConnectListDefinedStoragePools(virConnectPtr conn,
- char **const names,
- int nnames)
-{
- testDriverPtr privconn = conn->privateData;
- int n = 0;
- size_t i;
-
- testDriverLock(privconn);
- memset(names, 0, sizeof(*names)*nnames);
- for (i = 0; i < privconn->pools.count && n < nnames; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
- VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- goto error;
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- return n;
-
- error:
- for (n = 0; n < nnames; n++)
- VIR_FREE(names[n]);
- testDriverUnlock(privconn);
- return -1;
-}
-
-static int
-testConnectListAllStoragePools(virConnectPtr conn,
- virStoragePoolPtr **pools,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- int ret = -1;
-
- virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1);
-
- testDriverLock(privconn);
- ret = virStoragePoolObjListExport(conn, privconn->pools, pools,
- NULL, flags);
- testDriverUnlock(privconn);
-
- return ret;
-}
-
-static int testStoragePoolIsActive(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr obj;
- int ret = -1;
-
- testDriverLock(privconn);
- obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
- testDriverUnlock(privconn);
- if (!obj) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
- ret = virStoragePoolObjIsActive(obj);
-
- cleanup:
- if (obj)
- virStoragePoolObjUnlock(obj);
- return ret;
-}
-
-static int testStoragePoolIsPersistent(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr obj;
- int ret = -1;
-
- testDriverLock(privconn);
- obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
- testDriverUnlock(privconn);
- if (!obj) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
- goto cleanup;
- }
- ret = obj->configFile ? 1 : 0;
-
- cleanup:
- if (obj)
- virStoragePoolObjUnlock(obj);
- return ret;
-}
-
-
-
-static int
-testStoragePoolCreate(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
-
- privpool->active = 1;
-
- event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
- VIR_STORAGE_POOL_EVENT_STARTED,
- 0);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *type,
- const char *srcSpec,
- unsigned int flags)
-{
- virStoragePoolSourcePtr source = NULL;
- int pool_type;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- pool_type = virStoragePoolTypeFromString(type);
- if (!pool_type) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown storage pool type %s"), type);
- goto cleanup;
- }
-
- if (srcSpec) {
- source = virStoragePoolDefParseSourceString(srcSpec, pool_type);
- if (!source)
- goto cleanup;
- }
-
- switch (pool_type) {
-
- case VIR_STORAGE_POOL_LOGICAL:
- ignore_value(VIR_STRDUP(ret, defaultPoolSourcesLogicalXML));
- break;
-
- case VIR_STORAGE_POOL_NETFS:
- if (!source || !source->hosts[0].name) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("hostname must be specified for netfs sources"));
- goto cleanup;
- }
-
- ignore_value(virAsprintf(&ret, defaultPoolSourcesNetFSXML,
- source->hosts[0].name));
- break;
-
- default:
- virReportError(VIR_ERR_NO_SUPPORT,
- _("pool type '%s' does not support source discovery"), type);
- }
-
- cleanup:
- virStoragePoolSourceFree(source);
- return ret;
-}
-
-
-static virStoragePoolPtr
-testStoragePoolCreateXML(virConnectPtr conn,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolDefPtr def;
- virStoragePoolObjPtr pool = NULL;
- virStoragePoolPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- if (!(def = virStoragePoolDefParseString(xml)))
- goto cleanup;
-
- pool = virStoragePoolObjFindByUUID(&privconn->pools, def->uuid);
- if (!pool)
- pool = virStoragePoolObjFindByName(&privconn->pools, def->name);
- if (pool) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("storage pool already exists"));
- goto cleanup;
- }
-
- if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
- goto cleanup;
- def = NULL;
-
- if (testStoragePoolObjSetDefaults(pool) == -1) {
- virStoragePoolObjRemove(&privconn->pools, pool);
- pool = NULL;
- goto cleanup;
- }
- pool->active = 1;
-
- event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
- VIR_STORAGE_POOL_EVENT_STARTED,
- 0);
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- virStoragePoolDefFree(def);
- testObjectEventQueue(privconn, event);
- if (pool)
- virStoragePoolObjUnlock(pool);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static virStoragePoolPtr
-testStoragePoolDefineXML(virConnectPtr conn,
- const char *xml,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
- virStoragePoolDefPtr def;
- virStoragePoolObjPtr pool = NULL;
- virStoragePoolPtr ret = NULL;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- if (!(def = virStoragePoolDefParseString(xml)))
- goto cleanup;
-
- def->capacity = defaultPoolCap;
- def->allocation = defaultPoolAlloc;
- def->available = defaultPoolCap - defaultPoolAlloc;
-
- if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
- goto cleanup;
- def = NULL;
-
- event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
- VIR_STORAGE_POOL_EVENT_DEFINED,
- 0);
-
- if (testStoragePoolObjSetDefaults(pool) == -1) {
- virStoragePoolObjRemove(&privconn->pools, pool);
- pool = NULL;
- goto cleanup;
- }
-
- ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
- NULL, NULL);
-
- cleanup:
- virStoragePoolDefFree(def);
- testObjectEventQueue(privconn, event);
- if (pool)
- virStoragePoolObjUnlock(pool);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int
-testStoragePoolUndefine(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
-
- event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
- VIR_STORAGE_POOL_EVENT_UNDEFINED,
- 0);
-
- virStoragePoolObjRemove(&privconn->pools, privpool);
- privpool = NULL;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- testObjectEventQueue(privconn, event);
- testDriverUnlock(privconn);
- return ret;
-}
-
-static int
-testStoragePoolBuild(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolDestroy(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privpool->active = 0;
- event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid,
- VIR_STORAGE_POOL_EVENT_STOPPED,
- 0);
-
- if (privpool->configFile == NULL) {
- virStoragePoolObjRemove(&privconn->pools, privpool);
- privpool = NULL;
- }
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- testDriverUnlock(privconn);
- return ret;
-}
-
-
-static int
-testStoragePoolDelete(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is already active"), pool->name);
- goto cleanup;
- }
-
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolRefresh(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- event = virStoragePoolEventRefreshNew(pool->name, pool->uuid);
- ret = 0;
-
- cleanup:
- testObjectEventQueue(privconn, event);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolGetInfo(virStoragePoolPtr pool,
- virStoragePoolInfoPtr info)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- memset(info, 0, sizeof(virStoragePoolInfo));
- if (privpool->active)
- info->state = VIR_STORAGE_POOL_RUNNING;
- else
- info->state = VIR_STORAGE_POOL_INACTIVE;
- info->capacity = privpool->def->capacity;
- info->allocation = privpool->def->allocation;
- info->available = privpool->def->available;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testStoragePoolGetXMLDesc(virStoragePoolPtr pool,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- ret = virStoragePoolDefFormat(privpool->def);
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStoragePoolGetAutostart(virStoragePoolPtr pool,
- int *autostart)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!privpool->configFile) {
- *autostart = 0;
- } else {
- *autostart = privpool->autostart;
- }
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStoragePoolSetAutostart(virStoragePoolPtr pool,
- int autostart)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!privpool->configFile) {
- virReportError(VIR_ERR_INVALID_ARG,
- "%s", _("pool has no config file"));
- goto cleanup;
- }
-
- autostart = (autostart != 0);
- privpool->autostart = autostart;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int
-testStoragePoolNumOfVolumes(virStoragePoolPtr pool)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- ret = privpool->volumes.count;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStoragePoolListVolumes(virStoragePoolPtr pool,
- char **const names,
- int maxnames)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- size_t i = 0;
- int n = 0;
-
- memset(names, 0, maxnames * sizeof(*names));
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
- if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
- goto cleanup;
- }
-
- virStoragePoolObjUnlock(privpool);
- return n;
-
- cleanup:
- for (n = 0; n < maxnames; n++)
- VIR_FREE(names[i]);
-
- memset(names, 0, maxnames * sizeof(*names));
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return -1;
-}
-
-static int
-testStoragePoolListAllVolumes(virStoragePoolPtr obj,
- virStorageVolPtr **vols,
- unsigned int flags)
-{
- testDriverPtr privconn = obj->conn->privateData;
- virStoragePoolObjPtr pool;
- size_t i;
- virStorageVolPtr *tmp_vols = NULL;
- virStorageVolPtr vol = NULL;
- int nvols = 0;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid);
- testDriverUnlock(privconn);
-
- if (!pool) {
- virReportError(VIR_ERR_NO_STORAGE_POOL, "%s",
- _("no storage pool with matching uuid"));
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(pool)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("storage pool is not active"));
- goto cleanup;
- }
-
- /* Just returns the volumes count */
- if (!vols) {
- ret = pool->volumes.count;
- goto cleanup;
- }
-
- if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0)
- goto cleanup;
-
- for (i = 0; i < pool->volumes.count; i++) {
- if (!(vol = virGetStorageVol(obj->conn, pool->def->name,
- pool->volumes.objs[i]->name,
- pool->volumes.objs[i]->key,
- NULL, NULL)))
- goto cleanup;
- tmp_vols[nvols++] = vol;
- }
-
- *vols = tmp_vols;
- tmp_vols = NULL;
- ret = nvols;
-
- cleanup:
- if (tmp_vols) {
- for (i = 0; i < nvols; i++) {
- if (tmp_vols[i])
- virStorageVolFree(tmp_vols[i]);
- }
- VIR_FREE(tmp_vols);
- }
-
- if (pool)
- virStoragePoolObjUnlock(pool);
-
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolLookupByName(virStoragePoolPtr pool,
- const char *name ATTRIBUTE_UNUSED)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- virStorageVolPtr ret = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, name);
-
- if (!privvol) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"), name);
- goto cleanup;
- }
-
- ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key,
- NULL, NULL);
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static virStorageVolPtr
-testStorageVolLookupByKey(virConnectPtr conn,
- const char *key)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- virStorageVolPtr ret = NULL;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
- virStorageVolDefPtr privvol =
- virStorageVolDefFindByKey(privconn->pools.objs[i], key);
-
- if (privvol) {
- ret = virGetStorageVol(conn,
- privconn->pools.objs[i]->def->name,
- privvol->name,
- privvol->key,
- NULL, NULL);
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- break;
- }
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- if (!ret)
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching key '%s'"), key);
-
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolLookupByPath(virConnectPtr conn,
- const char *path)
-{
- testDriverPtr privconn = conn->privateData;
- size_t i;
- virStorageVolPtr ret = NULL;
-
- testDriverLock(privconn);
- for (i = 0; i < privconn->pools.count; i++) {
- virStoragePoolObjLock(privconn->pools.objs[i]);
- if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
- virStorageVolDefPtr privvol =
- virStorageVolDefFindByPath(privconn->pools.objs[i], path);
-
- if (privvol) {
- ret = virGetStorageVol(conn,
- privconn->pools.objs[i]->def->name,
- privvol->name,
- privvol->key,
- NULL, NULL);
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- break;
- }
- }
- virStoragePoolObjUnlock(privconn->pools.objs[i]);
- }
- testDriverUnlock(privconn);
-
- if (!ret)
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching path '%s'"), path);
-
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolCreateXML(virStoragePoolPtr pool,
- const char *xmldesc,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol = NULL;
- virStorageVolPtr ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
- if (privvol == NULL)
- goto cleanup;
-
- if (virStorageVolDefFindByName(privpool, privvol->name)) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("storage vol already exists"));
- goto cleanup;
- }
-
- /* Make sure enough space */
- if ((privpool->def->allocation + privvol->target.allocation) >
- privpool->def->capacity) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Not enough free space in pool for volume '%s'"),
- privvol->name);
- goto cleanup;
- }
-
- if (virAsprintf(&privvol->target.path, "%s/%s",
- privpool->def->target.path,
- privvol->name) == -1)
- goto cleanup;
-
- if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
- VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
- privpool->volumes.count, privvol) < 0)
- goto cleanup;
-
- privpool->def->allocation += privvol->target.allocation;
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key,
- NULL, NULL);
- privvol = NULL;
-
- cleanup:
- virStorageVolDefFree(privvol);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static virStorageVolPtr
-testStorageVolCreateXMLFrom(virStoragePoolPtr pool,
- const char *xmldesc,
- virStorageVolPtr clonevol,
- unsigned int flags)
-{
- testDriverPtr privconn = pool->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol = NULL, origvol = NULL;
- virStorageVolPtr ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- pool->name);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), pool->name);
- goto cleanup;
- }
-
- privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
- if (privvol == NULL)
- goto cleanup;
-
- if (virStorageVolDefFindByName(privpool, privvol->name)) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("storage vol already exists"));
- goto cleanup;
- }
-
- origvol = virStorageVolDefFindByName(privpool, clonevol->name);
- if (!origvol) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- clonevol->name);
- goto cleanup;
- }
-
- /* Make sure enough space */
- if ((privpool->def->allocation + privvol->target.allocation) >
- privpool->def->capacity) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Not enough free space in pool for volume '%s'"),
- privvol->name);
- goto cleanup;
- }
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- if (virAsprintf(&privvol->target.path, "%s/%s",
- privpool->def->target.path,
- privvol->name) == -1)
- goto cleanup;
-
- if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
- VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
- privpool->volumes.count, privvol) < 0)
- goto cleanup;
-
- privpool->def->allocation += privvol->target.allocation;
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- ret = virGetStorageVol(pool->conn, privpool->def->name,
- privvol->name, privvol->key,
- NULL, NULL);
- privvol = NULL;
-
- cleanup:
- virStorageVolDefFree(privvol);
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static int
-testStorageVolDelete(virStorageVolPtr vol,
- unsigned int flags)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- size_t i;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
-
- privpool->def->allocation -= privvol->target.allocation;
- privpool->def->available = (privpool->def->capacity -
- privpool->def->allocation);
-
- for (i = 0; i < privpool->volumes.count; i++) {
- if (privpool->volumes.objs[i] == privvol) {
- virStorageVolDefFree(privvol);
-
- VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
- break;
- }
- }
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-static int testStorageVolumeTypeForPool(int pooltype)
-{
-
- switch (pooltype) {
- case VIR_STORAGE_POOL_DIR:
- case VIR_STORAGE_POOL_FS:
- case VIR_STORAGE_POOL_NETFS:
- return VIR_STORAGE_VOL_FILE;
- default:
- return VIR_STORAGE_VOL_BLOCK;
- }
-}
-
-static int
-testStorageVolGetInfo(virStorageVolPtr vol,
- virStorageVolInfoPtr info)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- int ret = -1;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
- memset(info, 0, sizeof(*info));
- info->type = testStorageVolumeTypeForPool(privpool->def->type);
- info->capacity = privvol->target.capacity;
- info->allocation = privvol->target.allocation;
- ret = 0;
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testStorageVolGetXMLDesc(virStorageVolPtr vol,
- unsigned int flags)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
- ret = virStorageVolDefFormat(privpool->def, privvol);
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-static char *
-testStorageVolGetPath(virStorageVolPtr vol)
-{
- testDriverPtr privconn = vol->conn->privateData;
- virStoragePoolObjPtr privpool;
- virStorageVolDefPtr privvol;
- char *ret = NULL;
-
- testDriverLock(privconn);
- privpool = virStoragePoolObjFindByName(&privconn->pools,
- vol->pool);
- testDriverUnlock(privconn);
-
- if (privpool == NULL) {
- virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto cleanup;
- }
-
- privvol = virStorageVolDefFindByName(privpool, vol->name);
-
- if (privvol == NULL) {
- virReportError(VIR_ERR_NO_STORAGE_VOL,
- _("no storage vol with matching name '%s'"),
- vol->name);
- goto cleanup;
- }
-
- if (!virStoragePoolObjIsActive(privpool)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("storage pool '%s' is not active"), vol->pool);
- goto cleanup;
- }
-
- ignore_value(VIR_STRDUP(ret, privvol->target.path));
-
- cleanup:
- if (privpool)
- virStoragePoolObjUnlock(privpool);
- return ret;
-}
-
-
-/* Node device implementations */
-
-static int
-testNodeNumOfDevices(virConnectPtr conn,
- const char *cap,
- unsigned int flags)
-{
- testDriverPtr driver = conn->privateData;
- int ndevs = 0;
- size_t i;
-
- virCheckFlags(0, -1);
-
- testDriverLock(driver);
- for (i = 0; i < driver->devs.count; i++)
- if ((cap == NULL) ||
- virNodeDeviceHasCap(driver->devs.objs[i], cap))
- ++ndevs;
- testDriverUnlock(driver);
-
- return ndevs;
-}
-
-static int
-testNodeListDevices(virConnectPtr conn,
- const char *cap,
- char **const names,
- int maxnames,
- unsigned int flags)
-{
- testDriverPtr driver = conn->privateData;
- int ndevs = 0;
- size_t i;
-
- virCheckFlags(0, -1);
-
- testDriverLock(driver);
- for (i = 0; i < driver->devs.count && ndevs < maxnames; i++) {
- virNodeDeviceObjLock(driver->devs.objs[i]);
- if (cap == NULL ||
- virNodeDeviceHasCap(driver->devs.objs[i], cap)) {
- if (VIR_STRDUP(names[ndevs++], driver->devs.objs[i]->def->name) < 0) {
- virNodeDeviceObjUnlock(driver->devs.objs[i]);
- goto failure;
- }
- }
- virNodeDeviceObjUnlock(driver->devs.objs[i]);
- }
- testDriverUnlock(driver);
-
- return ndevs;
-
- failure:
- testDriverUnlock(driver);
- --ndevs;
- while (--ndevs >= 0)
- VIR_FREE(names[ndevs]);
- return -1;
-}
-
-static virNodeDevicePtr
-testNodeDeviceLookupByName(virConnectPtr conn, const char *name)
-{
- testDriverPtr driver = conn->privateData;
- virNodeDeviceObjPtr obj;
- virNodeDevicePtr ret = NULL;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- name);
- goto cleanup;
- }
-
- ret = virGetNodeDevice(conn, name);
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-static char *
-testNodeDeviceGetXMLDesc(virNodeDevicePtr dev,
- unsigned int flags)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- ret = virNodeDeviceDefFormat(obj->def);
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-static char *
-testNodeDeviceGetParent(virNodeDevicePtr dev)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- char *ret = NULL;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- if (obj->def->parent) {
- ignore_value(VIR_STRDUP(ret, obj->def->parent));
- } else {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("no parent for this device"));
- }
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-
-static int
-testNodeDeviceNumOfCaps(virNodeDevicePtr dev)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- virNodeDevCapsDefPtr caps;
- int ncaps = 0;
- int ret = -1;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- for (caps = obj->def->caps; caps; caps = caps->next)
- ++ncaps;
- ret = ncaps;
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- return ret;
-}
-
-
-static int
-testNodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
-{
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj;
- virNodeDevCapsDefPtr caps;
- int ncaps = 0;
- int ret = -1;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto cleanup;
- }
-
- for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
- if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0)
- goto cleanup;
- }
- ret = ncaps;
-
- cleanup:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- if (ret == -1) {
- --ncaps;
- while (--ncaps >= 0)
- VIR_FREE(names[ncaps]);
- }
- return ret;
-}
-
-static virNodeDevicePtr
-testNodeDeviceCreateXML(virConnectPtr conn,
- const char *xmlDesc,
- unsigned int flags)
-{
- testDriverPtr driver = conn->privateData;
- virNodeDeviceDefPtr def = NULL;
- virNodeDeviceObjPtr obj = NULL;
- char *wwnn = NULL, *wwpn = NULL;
- int parent_host = -1;
- virNodeDevicePtr dev = NULL;
- virNodeDevCapsDefPtr caps;
- virObjectEventPtr event = NULL;
-
- virCheckFlags(0, NULL);
-
- testDriverLock(driver);
-
- def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, NULL);
- if (def == NULL)
- goto cleanup;
-
- /* We run these next two simply for validation */
- if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
- goto cleanup;
-
- if (virNodeDeviceGetParentHost(&driver->devs,
- def->name,
- def->parent,
- &parent_host) == -1) {
- goto cleanup;
- }
-
- /* 'name' is supposed to be filled in by the node device backend, which
- * we don't have. Use WWPN instead. */
- VIR_FREE(def->name);
- if (VIR_STRDUP(def->name, wwpn) < 0)
- goto cleanup;
-
- /* Fill in a random 'host' and 'unique_id' value,
- * since this would also come from the backend */
- caps = def->caps;
- while (caps) {
- if (caps->data.type != VIR_NODE_DEV_CAP_SCSI_HOST)
- continue;
-
- caps->data.scsi_host.host = virRandomBits(10);
- caps->data.scsi_host.unique_id = 2;
- caps = caps->next;
- }
-
-
- if (!(obj = virNodeDeviceAssignDef(&driver->devs, def)))
- goto cleanup;
- virNodeDeviceObjUnlock(obj);
-
- event = virNodeDeviceEventLifecycleNew(def->name,
- VIR_NODE_DEVICE_EVENT_CREATED,
- 0);
-
- dev = virGetNodeDevice(conn, def->name);
- def = NULL;
- cleanup:
- testDriverUnlock(driver);
- virNodeDeviceDefFree(def);
- testObjectEventQueue(driver, event);
- VIR_FREE(wwnn);
- VIR_FREE(wwpn);
- return dev;
-}
-
-static int
-testNodeDeviceDestroy(virNodeDevicePtr dev)
-{
- int ret = 0;
- testDriverPtr driver = dev->conn->privateData;
- virNodeDeviceObjPtr obj = NULL;
- char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
- int parent_host = -1;
- virObjectEventPtr event = NULL;
-
- testDriverLock(driver);
- obj = virNodeDeviceFindByName(&driver->devs, dev->name);
- testDriverUnlock(driver);
-
- if (!obj) {
- virReportError(VIR_ERR_NO_NODE_DEVICE,
- _("no node device with matching name '%s'"),
- dev->name);
- goto out;
- }
-
- if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1)
- goto out;
-
- if (VIR_STRDUP(parent_name, obj->def->parent) < 0)
- goto out;
-
- /* virNodeDeviceGetParentHost will cause the device object's lock to be
- * taken, so we have to dup the parent's name and drop the lock
- * before calling it. We don't need the reference to the object
- * any more once we have the parent's name. */
- virNodeDeviceObjUnlock(obj);
-
- /* We do this just for basic validation */
- if (virNodeDeviceGetParentHost(&driver->devs,
- dev->name,
- parent_name,
- &parent_host) == -1) {
- obj = NULL;
- goto out;
- }
-
- event = virNodeDeviceEventLifecycleNew(dev->name,
- VIR_NODE_DEVICE_EVENT_DELETED,
- 0);
-
- virNodeDeviceObjLock(obj);
- virNodeDeviceObjRemove(&driver->devs, &obj);
-
- out:
- if (obj)
- virNodeDeviceObjUnlock(obj);
- testObjectEventQueue(driver, event);
- VIR_FREE(parent_name);
- VIR_FREE(wwnn);
- VIR_FREE(wwpn);
- return ret;
-}
-
-
-/* Domain event implementations */
-static int
-testConnectDomainEventRegister(virConnectPtr conn,
- virConnectDomainEventCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virDomainEventStateRegister(conn, driver->eventState,
- callback, opaque, freecb) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int
-testConnectDomainEventDeregister(virConnectPtr conn,
- virConnectDomainEventCallback callback)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virDomainEventStateDeregister(conn, driver->eventState,
- callback) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int
-testConnectDomainEventRegisterAny(virConnectPtr conn,
- virDomainPtr dom,
- int eventID,
- virConnectDomainEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virDomainEventStateRegisterID(conn, driver->eventState,
- dom, eventID,
- callback, opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectDomainEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-
-static int
-testConnectNetworkEventRegisterAny(virConnectPtr conn,
- virNetworkPtr net,
- int eventID,
- virConnectNetworkEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virNetworkEventStateRegisterID(conn, driver->eventState,
- net, eventID, callback,
- opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectNetworkEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectStoragePoolEventRegisterAny(virConnectPtr conn,
- virStoragePoolPtr pool,
- int eventID,
- virConnectStoragePoolEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virStoragePoolEventStateRegisterID(conn, driver->eventState,
- pool, eventID, callback,
- opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
- virNodeDevicePtr dev,
- int eventID,
- virConnectNodeDeviceEventGenericCallback callback,
- void *opaque,
- virFreeCallback freecb)
-{
- testDriverPtr driver = conn->privateData;
- int ret;
-
- if (virNodeDeviceEventStateRegisterID(conn, driver->eventState,
- dev, eventID, callback,
- opaque, freecb, &ret) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int
-testConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
- int callbackID)
-{
- testDriverPtr driver = conn->privateData;
- int ret = 0;
-
- if (virObjectEventStateDeregisterID(conn, driver->eventState,
- callbackID) < 0)
- ret = -1;
-
- return ret;
-}
-
-static int testConnectListAllDomains(virConnectPtr conn,
- virDomainPtr **domains,
- unsigned int flags)
-{
- testDriverPtr privconn = conn->privateData;
-
- virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
-
- return virDomainObjListExport(privconn->domains, conn, domains,
- NULL, flags);
-}
-
-static int
-testNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
- unsigned char **cpumap,
- unsigned int *online,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
-
- if (cpumap) {
- if (VIR_ALLOC_N(*cpumap, 1) < 0)
- return -1;
- *cpumap[0] = 0x15;
- }
-
- if (online)
- *online = 3;
-
- return 8;
-}
-
-static char *
-testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED,
- virStreamPtr st,
- unsigned int screen ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- char *ret = NULL;
-
- virCheckFlags(0, NULL);
-
- if (VIR_STRDUP(ret, "image/png") < 0)
- return NULL;
-
- if (virFDStreamOpenFile(st, PKGDATADIR "/libvirtLogo.png", 0, 0, O_RDONLY) < 0)
- VIR_FREE(ret);
-
- return ret;
-}
-
-static int
-testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED,
- const char *arch,
- char ***models,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
- return cpuGetModels(arch, models);
-}
-
-static int
-testDomainManagedSave(virDomainPtr dom, unsigned int flags)
-{
- testDriverPtr privconn = dom->conn->privateData;
- virDomainObjPtr vm = NULL;
- virObjectEventPtr event = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
- VIR_DOMAIN_SAVE_RUNNING |
- VIR_DOMAIN_SAVE_PAUSED, -1);
-
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- if (!virDomainObjIsActive(vm)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
- if (!vm->persistent) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot do managed save for transient domain"));
- goto cleanup;
- }
-
- testDomainShutdownState(dom, vm, VIR_DOMAIN_SHUTOFF_SAVED);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SAVED);
- vm->hasManagedSave = true;
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&vm);
- testObjectEventQueue(privconn, event);
-
- return ret;
-}
-
-
-static int
-testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
-{
- virDomainObjPtr vm;
- int ret;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- ret = vm->hasManagedSave;
-
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
-{
- virDomainObjPtr vm;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromDomain(dom)))
- return -1;
-
- vm->hasManagedSave = false;
-
- virDomainObjEndAPI(&vm);
- return 0;
-}
-
-
-/*
- * Snapshot APIs
- */
-
-static virDomainSnapshotObjPtr
-testSnapObjFromName(virDomainObjPtr vm,
- const char *name)
-{
- virDomainSnapshotObjPtr snap = NULL;
- snap = virDomainSnapshotFindByName(vm->snapshots, name);
- if (!snap)
- virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
- _("no domain snapshot with matching name '%s'"),
- name);
- return snap;
-}
-
-static virDomainSnapshotObjPtr
-testSnapObjFromSnapshot(virDomainObjPtr vm,
- virDomainSnapshotPtr snapshot)
-{
- return testSnapObjFromName(vm, snapshot->name);
-}
-
-static virDomainObjPtr
-testDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
-{
- return testDomObjFromDomain(snapshot->domain);
-}
-
-static int
-testDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int n;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
-
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotListNames(virDomainPtr domain,
- char **names,
- int nameslen,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int n;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
- flags);
-
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainListAllSnapshots(virDomainPtr domain,
- virDomainSnapshotPtr **snaps,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int n;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
-
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
- char **names,
- int nameslen,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- int n = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
- flags);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- int n = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static int
-testDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
- virDomainSnapshotPtr **snaps,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- int n = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
- VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
- flags);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return n;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotLookupByName(virDomainPtr domain,
- const char *name,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotPtr snapshot = NULL;
-
- virCheckFlags(0, NULL);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return NULL;
-
- if (!(snap = testSnapObjFromName(vm, name)))
- goto cleanup;
-
- snapshot = virGetDomainSnapshot(domain, snap->def->name);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return snapshot;
-}
-
-static int
-testDomainHasCurrentSnapshot(virDomainPtr domain,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- int ret;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return -1;
-
- ret = (vm->current_snapshot != NULL);
-
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotPtr parent = NULL;
-
- virCheckFlags(0, NULL);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return NULL;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- if (!snap->def->parent) {
- virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
- _("snapshot '%s' does not have a parent"),
- snap->def->name);
- goto cleanup;
- }
-
- parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return parent;
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotCurrent(virDomainPtr domain,
- unsigned int flags)
-{
- virDomainObjPtr vm;
- virDomainSnapshotPtr snapshot = NULL;
-
- virCheckFlags(0, NULL);
-
- if (!(vm = testDomObjFromDomain(domain)))
- return NULL;
-
- if (!vm->current_snapshot) {
- virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
- _("the domain does not have a current snapshot"));
- goto cleanup;
- }
-
- snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return snapshot;
-}
-
-static char *
-testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- char *xml = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- testDriverPtr privconn = snapshot->domain->conn->privateData;
-
- virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return NULL;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- virUUIDFormat(snapshot->domain->uuid, uuidstr);
-
- xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
- virDomainDefFormatConvertXMLFlags(flags),
- 0);
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return xml;
-}
-
-static int
-testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int ret;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- ret = (vm->current_snapshot &&
- STREQ(snapshot->name, vm->current_snapshot->def->name));
-
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-
-static int
-testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- int ret = -1;
-
- virCheckFlags(0, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!testSnapObjFromSnapshot(vm, snapshot))
- goto cleanup;
-
- ret = 1;
-
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainSnapshotAlignDisks(virDomainObjPtr vm,
- virDomainSnapshotDefPtr def,
- unsigned int flags)
-{
- int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
- bool align_match = true;
-
- if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
- align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
- align_match = false;
- if (virDomainObjIsActive(vm))
- def->state = VIR_DOMAIN_DISK_SNAPSHOT;
- else
- def->state = VIR_DOMAIN_SHUTOFF;
- def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
- } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
- def->state = virDomainObjGetState(vm, NULL);
- align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
- align_match = false;
- } else {
- def->state = virDomainObjGetState(vm, NULL);
- def->memory = def->state == VIR_DOMAIN_SHUTOFF ?
- VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
- VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
- }
-
- return virDomainSnapshotAlignDisks(def, align_location, align_match);
-}
-
-static virDomainSnapshotPtr
-testDomainSnapshotCreateXML(virDomainPtr domain,
- const char *xmlDesc,
- unsigned int flags)
-{
- testDriverPtr privconn = domain->conn->privateData;
- virDomainObjPtr vm = NULL;
- virDomainSnapshotDefPtr def = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotPtr snapshot = NULL;
- virObjectEventPtr event = NULL;
- char *xml = NULL;
- bool update_current = true;
- bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
- unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
-
- /*
- * DISK_ONLY: Not implemented yet
- * REUSE_EXT: Not implemented yet
- *
- * NO_METADATA: Explicitly not implemented
- *
- * REDEFINE + CURRENT: Implemented
- * HALT: Implemented
- * QUIESCE: Nothing to do
- * ATOMIC: Nothing to do
- * LIVE: Nothing to do
- */
- virCheckFlags(
- VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
- VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
- VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
- VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
- VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
- VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
-
- if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)))
- update_current = false;
- if (redefine)
- parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
-
- if (!(vm = testDomObjFromDomain(domain)))
- goto cleanup;
-
- if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot halt after transient domain snapshot"));
- goto cleanup;
- }
-
- if (!(def = virDomainSnapshotDefParseString(xmlDesc,
- privconn->caps,
- privconn->xmlopt,
- parse_flags)))
- goto cleanup;
-
- if (redefine) {
- if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
- &update_current, flags) < 0)
- goto cleanup;
- } else {
- if (!(def->dom = virDomainDefCopy(vm->def,
- privconn->caps,
- privconn->xmlopt,
- true)))
- goto cleanup;
-
- if (testDomainSnapshotAlignDisks(vm, def, flags) < 0)
- goto cleanup;
- }
-
- if (!snap) {
- if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
- goto cleanup;
- def = NULL;
- }
-
- if (!redefine) {
- if (vm->current_snapshot &&
- (VIR_STRDUP(snap->def->parent,
- vm->current_snapshot->def->name) < 0))
- goto cleanup;
-
- if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
- virDomainObjIsActive(vm)) {
- testDomainShutdownState(domain, vm,
- VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
- event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
- }
- }
-
- snapshot = virGetDomainSnapshot(domain, snap->def->name);
- cleanup:
- VIR_FREE(xml);
- if (vm) {
- if (snapshot) {
- virDomainSnapshotObjPtr other;
- if (update_current)
- vm->current_snapshot = snap;
- other = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent);
- snap->parent = other;
- other->nchildren++;
- snap->sibling = other->first_child;
- other->first_child = snap;
- }
- virDomainObjEndAPI(&vm);
- }
- testObjectEventQueue(privconn, event);
- virDomainSnapshotDefFree(def);
- return snapshot;
-}
-
-
-typedef struct _testSnapRemoveData testSnapRemoveData;
-typedef testSnapRemoveData *testSnapRemoveDataPtr;
-struct _testSnapRemoveData {
- virDomainObjPtr vm;
- bool current;
-};
-
-static int
-testDomainSnapshotDiscardAll(void *payload,
- const void *name ATTRIBUTE_UNUSED,
- void *data)
-{
- virDomainSnapshotObjPtr snap = payload;
- testSnapRemoveDataPtr curr = data;
-
- if (snap->def->current)
- curr->current = true;
- virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
- return 0;
-}
-
-typedef struct _testSnapReparentData testSnapReparentData;
-typedef testSnapReparentData *testSnapReparentDataPtr;
-struct _testSnapReparentData {
- virDomainSnapshotObjPtr parent;
- virDomainObjPtr vm;
- int err;
- virDomainSnapshotObjPtr last;
-};
-
-static int
-testDomainSnapshotReparentChildren(void *payload,
- const void *name ATTRIBUTE_UNUSED,
- void *data)
-{
- virDomainSnapshotObjPtr snap = payload;
- testSnapReparentDataPtr rep = data;
-
- if (rep->err < 0)
- return 0;
-
- VIR_FREE(snap->def->parent);
- snap->parent = rep->parent;
-
- if (rep->parent->def &&
- VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
- rep->err = -1;
- return 0;
- }
-
- if (!snap->sibling)
- rep->last = snap;
- return 0;
-}
-
-static int
-testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- virDomainSnapshotObjPtr parentsnap = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
- VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
- VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
- testSnapRemoveData rem;
- rem.vm = vm;
- rem.current = false;
- virDomainSnapshotForEachDescendant(snap,
- testDomainSnapshotDiscardAll,
- &rem);
- if (rem.current) {
- if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
- snap->def->current = true;
- vm->current_snapshot = snap;
- }
- } else if (snap->nchildren) {
- testSnapReparentData rep;
- rep.parent = snap->parent;
- rep.vm = vm;
- rep.err = 0;
- rep.last = NULL;
- virDomainSnapshotForEachChild(snap,
- testDomainSnapshotReparentChildren,
- &rep);
- if (rep.err < 0)
- goto cleanup;
-
- /* Can't modify siblings during ForEachChild, so do it now. */
- snap->parent->nchildren += snap->nchildren;
- rep.last->sibling = snap->parent->first_child;
- snap->parent->first_child = snap->first_child;
- }
-
- if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
- snap->nchildren = 0;
- snap->first_child = NULL;
- } else {
- virDomainSnapshotDropParent(snap);
- if (snap == vm->current_snapshot) {
- if (snap->def->parent) {
- parentsnap = virDomainSnapshotFindByName(vm->snapshots,
- snap->def->parent);
- if (!parentsnap) {
- VIR_WARN("missing parent snapshot matching name '%s'",
- snap->def->parent);
- } else {
- parentsnap->def->current = true;
- }
- }
- vm->current_snapshot = parentsnap;
- }
- virDomainSnapshotObjListRemove(vm->snapshots, snap);
- }
-
- ret = 0;
- cleanup:
- virDomainObjEndAPI(&vm);
- return ret;
-}
-
-static int
-testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
- unsigned int flags)
-{
- testDriverPtr privconn = snapshot->domain->conn->privateData;
- virDomainObjPtr vm = NULL;
- virDomainSnapshotObjPtr snap = NULL;
- virObjectEventPtr event = NULL;
- virObjectEventPtr event2 = NULL;
- virDomainDefPtr config = NULL;
- int ret = -1;
-
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
- VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
-
- /* We have the following transitions, which create the following events:
- * 1. inactive -> inactive: none
- * 2. inactive -> running: EVENT_STARTED
- * 3. inactive -> paused: EVENT_STARTED, EVENT_PAUSED
- * 4. running -> inactive: EVENT_STOPPED
- * 5. running -> running: none
- * 6. running -> paused: EVENT_PAUSED
- * 7. paused -> inactive: EVENT_STOPPED
- * 8. paused -> running: EVENT_RESUMED
- * 9. paused -> paused: none
- * Also, several transitions occur even if we fail partway through,
- * and use of FORCE can cause multiple transitions.
- */
-
- if (!(vm = testDomObjFromSnapshot(snapshot)))
- return -1;
-
- if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
- goto cleanup;
-
- if (!vm->persistent &&
- snap->def->state != VIR_DOMAIN_RUNNING &&
- snap->def->state != VIR_DOMAIN_PAUSED &&
- (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
- virReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("transient domain needs to request run or pause "
- "to revert to inactive snapshot"));
- goto cleanup;
- }
-
- if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
- if (!snap->def->dom) {
- virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
- _("snapshot '%s' lacks domain '%s' rollback info"),
- snap->def->name, vm->def->name);
- goto cleanup;
- }
- if (virDomainObjIsActive(vm) &&
- !(snap->def->state == VIR_DOMAIN_RUNNING
- || snap->def->state == VIR_DOMAIN_PAUSED) &&
- (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
- virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
- _("must respawn guest to start inactive snapshot"));
- goto cleanup;
- }
- }
-
-
- if (vm->current_snapshot) {
- vm->current_snapshot->def->current = false;
- vm->current_snapshot = NULL;
- }
-
- snap->def->current = true;
- config = virDomainDefCopy(snap->def->dom,
- privconn->caps, privconn->xmlopt, true);
- if (!config)
- goto cleanup;
-
- if (snap->def->state == VIR_DOMAIN_RUNNING ||
- snap->def->state == VIR_DOMAIN_PAUSED) {
- /* Transitions 2, 3, 5, 6, 8, 9 */
- bool was_running = false;
- bool was_stopped = false;
-
- if (virDomainObjIsActive(vm)) {
- /* Transitions 5, 6, 8, 9 */
- /* Check for ABI compatibility. */
- if (!virDomainDefCheckABIStability(vm->def, config)) {
- virErrorPtr err = virGetLastError();
-
- if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
- /* Re-spawn error using correct category. */
- if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
- virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
- err->str2);
- goto cleanup;
- }
-
- virResetError(err);
- testDomainShutdownState(snapshot->domain, vm,
- VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
- testObjectEventQueue(privconn, event);
- goto load;
- }
-
- if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
- /* Transitions 5, 6 */
- was_running = true;
- virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
- VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
- /* Create an event now in case the restore fails, so
- * that user will be alerted that they are now paused.
- * If restore later succeeds, we might replace this. */
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- }
- virDomainObjAssignDef(vm, config, false, NULL);
-
- } else {
- /* Transitions 2, 3 */
- load:
- was_stopped = true;
- virDomainObjAssignDef(vm, config, false, NULL);
- if (testDomainStartState(privconn, vm,
- VIR_DOMAIN_RUNNING_FROM_SNAPSHOT) < 0)
- goto cleanup;
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
- }
-
- /* Touch up domain state. */
- if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
- (snap->def->state == VIR_DOMAIN_PAUSED ||
- (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
- /* Transitions 3, 6, 9 */
- virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
- VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
- if (was_stopped) {
- /* Transition 3, use event as-is and add event2 */
- event2 = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- } /* else transition 6 and 9 use event as-is */
- } else {
- /* Transitions 2, 5, 8 */
- virObjectUnref(event);
- event = NULL;
-
- if (was_stopped) {
- /* Transition 2 */
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
- } else if (was_running) {
- /* Transition 8 */
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_RESUMED,
- VIR_DOMAIN_EVENT_RESUMED);
- }
- }
- } else {
- /* Transitions 1, 4, 7 */
- virDomainObjAssignDef(vm, config, false, NULL);
-
- if (virDomainObjIsActive(vm)) {
- /* Transitions 4, 7 */
- testDomainShutdownState(snapshot->domain, vm,
- VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
- }
-
- if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
- VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
- /* Flush first event, now do transition 2 or 3 */
- bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
-
- testObjectEventQueue(privconn, event);
- event = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
- if (paused) {
- event2 = virDomainEventLifecycleNewFromObj(vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
- }
- }
- }
-
- vm->current_snapshot = snap;
- ret = 0;
- cleanup:
- if (event) {
- testObjectEventQueue(privconn, event);
- testObjectEventQueue(privconn, event2);
- } else {
- virObjectUnref(event2);
- }
- virDomainObjEndAPI(&vm);
-
- return ret;
-}
-
-
-
-static virHypervisorDriver testHypervisorDriver = {
- .name = "Test",
- .connectOpen = testConnectOpen, /* 0.1.1 */
- .connectClose = testConnectClose, /* 0.1.1 */
- .connectGetVersion = testConnectGetVersion, /* 0.1.1 */
- .connectGetHostname = testConnectGetHostname, /* 0.6.3 */
- .connectGetMaxVcpus = testConnectGetMaxVcpus, /* 0.3.2 */
- .nodeGetInfo = testNodeGetInfo, /* 0.1.1 */
- .nodeGetCPUStats = testNodeGetCPUStats, /* 2.3.0 */
- .nodeGetFreeMemory = testNodeGetFreeMemory, /* 2.3.0 */
- .nodeGetFreePages = testNodeGetFreePages, /* 2.3.0 */
- .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */
- .connectGetSysinfo = testConnectGetSysinfo, /* 2.3.0 */
- .connectGetType = testConnectGetType, /* 2.3.0 */
- .connectListDomains = testConnectListDomains, /* 0.1.1 */
- .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
- .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
- .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
- .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
- .domainLookupByUUID = testDomainLookupByUUID, /* 0.1.1 */
- .domainLookupByName = testDomainLookupByName, /* 0.1.1 */
- .domainSuspend = testDomainSuspend, /* 0.1.1 */
- .domainResume = testDomainResume, /* 0.1.1 */
- .domainShutdown = testDomainShutdown, /* 0.1.1 */
- .domainShutdownFlags = testDomainShutdownFlags, /* 0.9.10 */
- .domainReboot = testDomainReboot, /* 0.1.1 */
- .domainDestroy = testDomainDestroy, /* 0.1.1 */
- .domainGetOSType = testDomainGetOSType, /* 0.1.9 */
- .domainGetMaxMemory = testDomainGetMaxMemory, /* 0.1.4 */
- .domainSetMaxMemory = testDomainSetMaxMemory, /* 0.1.1 */
- .domainSetMemory = testDomainSetMemory, /* 0.1.4 */
- .domainGetInfo = testDomainGetInfo, /* 0.1.1 */
- .domainGetState = testDomainGetState, /* 0.9.2 */
- .domainSave = testDomainSave, /* 0.3.2 */
- .domainSaveFlags = testDomainSaveFlags, /* 0.9.4 */
- .domainRestore = testDomainRestore, /* 0.3.2 */
- .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */
- .domainCoreDump = testDomainCoreDump, /* 0.3.2 */
- .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */
- .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */
- .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */
- .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */
- .domainPinVcpu = testDomainPinVcpu, /* 0.7.3 */
- .domainGetVcpus = testDomainGetVcpus, /* 0.7.3 */
- .domainGetVcpuPinInfo = testDomainGetVcpuPinInfo, /* 1.2.18 */
- .domainGetMaxVcpus = testDomainGetMaxVcpus, /* 0.7.3 */
- .domainGetXMLDesc = testDomainGetXMLDesc, /* 0.1.4 */
- .connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
- .connectNumOfDefinedDomains = testConnectNumOfDefinedDomains, /* 0.1.11 */
- .domainCreate = testDomainCreate, /* 0.1.11 */
- .domainCreateWithFlags = testDomainCreateWithFlags, /* 0.8.2 */
- .domainDefineXML = testDomainDefineXML, /* 0.1.11 */
- .domainDefineXMLFlags = testDomainDefineXMLFlags, /* 1.2.12 */
- .domainUndefine = testDomainUndefine, /* 0.1.11 */
- .domainUndefineFlags = testDomainUndefineFlags, /* 0.9.4 */
- .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */
- .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */
- .domainGetSchedulerType = testDomainGetSchedulerType, /* 0.3.2 */
- .domainGetSchedulerParameters = testDomainGetSchedulerParameters, /* 0.3.2 */
- .domainGetSchedulerParametersFlags = testDomainGetSchedulerParametersFlags, /* 0.9.2 */
- .domainSetSchedulerParameters = testDomainSetSchedulerParameters, /* 0.3.2 */
- .domainSetSchedulerParametersFlags = testDomainSetSchedulerParametersFlags, /* 0.9.2 */
- .domainBlockStats = testDomainBlockStats, /* 0.7.0 */
- .domainInterfaceStats = testDomainInterfaceStats, /* 0.7.0 */
- .nodeGetCellsFreeMemory = testNodeGetCellsFreeMemory, /* 0.4.2 */
- .connectDomainEventRegister = testConnectDomainEventRegister, /* 0.6.0 */
- .connectDomainEventDeregister = testConnectDomainEventDeregister, /* 0.6.0 */
- .connectIsEncrypted = testConnectIsEncrypted, /* 0.7.3 */
- .connectIsSecure = testConnectIsSecure, /* 0.7.3 */
- .domainIsActive = testDomainIsActive, /* 0.7.3 */
- .domainIsPersistent = testDomainIsPersistent, /* 0.7.3 */
- .domainIsUpdated = testDomainIsUpdated, /* 0.8.6 */
- .connectDomainEventRegisterAny = testConnectDomainEventRegisterAny, /* 0.8.0 */
- .connectDomainEventDeregisterAny = testConnectDomainEventDeregisterAny, /* 0.8.0 */
- .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
- .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
- .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
- .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
- .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
- .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.3 */
- .domainManagedSave = testDomainManagedSave, /* 1.1.4 */
- .domainHasManagedSaveImage = testDomainHasManagedSaveImage, /* 1.1.4 */
- .domainManagedSaveRemove = testDomainManagedSaveRemove, /* 1.1.4 */
-
- .domainSnapshotNum = testDomainSnapshotNum, /* 1.1.4 */
- .domainSnapshotListNames = testDomainSnapshotListNames, /* 1.1.4 */
- .domainListAllSnapshots = testDomainListAllSnapshots, /* 1.1.4 */
- .domainSnapshotGetXMLDesc = testDomainSnapshotGetXMLDesc, /* 1.1.4 */
- .domainSnapshotNumChildren = testDomainSnapshotNumChildren, /* 1.1.4 */
- .domainSnapshotListChildrenNames = testDomainSnapshotListChildrenNames, /* 1.1.4 */
- .domainSnapshotListAllChildren = testDomainSnapshotListAllChildren, /* 1.1.4 */
- .domainSnapshotLookupByName = testDomainSnapshotLookupByName, /* 1.1.4 */
- .domainHasCurrentSnapshot = testDomainHasCurrentSnapshot, /* 1.1.4 */
- .domainSnapshotGetParent = testDomainSnapshotGetParent, /* 1.1.4 */
- .domainSnapshotCurrent = testDomainSnapshotCurrent, /* 1.1.4 */
- .domainSnapshotIsCurrent = testDomainSnapshotIsCurrent, /* 1.1.4 */
- .domainSnapshotHasMetadata = testDomainSnapshotHasMetadata, /* 1.1.4 */
- .domainSnapshotCreateXML = testDomainSnapshotCreateXML, /* 1.1.4 */
- .domainRevertToSnapshot = testDomainRevertToSnapshot, /* 1.1.4 */
- .domainSnapshotDelete = testDomainSnapshotDelete, /* 1.1.4 */
-
- .connectBaselineCPU = testConnectBaselineCPU, /* 1.2.0 */
-};
-
-static virNetworkDriver testNetworkDriver = {
- .connectNumOfNetworks = testConnectNumOfNetworks, /* 0.3.2 */
- .connectListNetworks = testConnectListNetworks, /* 0.3.2 */
- .connectNumOfDefinedNetworks = testConnectNumOfDefinedNetworks, /* 0.3.2 */
- .connectListDefinedNetworks = testConnectListDefinedNetworks, /* 0.3.2 */
- .connectListAllNetworks = testConnectListAllNetworks, /* 0.10.2 */
- .connectNetworkEventRegisterAny = testConnectNetworkEventRegisterAny, /* 1.2.1 */
- .connectNetworkEventDeregisterAny = testConnectNetworkEventDeregisterAny, /* 1.2.1 */
- .networkLookupByUUID = testNetworkLookupByUUID, /* 0.3.2 */
- .networkLookupByName = testNetworkLookupByName, /* 0.3.2 */
- .networkCreateXML = testNetworkCreateXML, /* 0.3.2 */
- .networkDefineXML = testNetworkDefineXML, /* 0.3.2 */
- .networkUndefine = testNetworkUndefine, /* 0.3.2 */
- .networkUpdate = testNetworkUpdate, /* 0.10.2 */
- .networkCreate = testNetworkCreate, /* 0.3.2 */
- .networkDestroy = testNetworkDestroy, /* 0.3.2 */
- .networkGetXMLDesc = testNetworkGetXMLDesc, /* 0.3.2 */
- .networkGetBridgeName = testNetworkGetBridgeName, /* 0.3.2 */
- .networkGetAutostart = testNetworkGetAutostart, /* 0.3.2 */
- .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
- .networkIsActive = testNetworkIsActive, /* 0.7.3 */
- .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
-};
-
-static virInterfaceDriver testInterfaceDriver = {
- .connectNumOfInterfaces = testConnectNumOfInterfaces, /* 0.7.0 */
- .connectListInterfaces = testConnectListInterfaces, /* 0.7.0 */
- .connectNumOfDefinedInterfaces = testConnectNumOfDefinedInterfaces, /* 0.7.0 */
- .connectListDefinedInterfaces = testConnectListDefinedInterfaces, /* 0.7.0 */
- .interfaceLookupByName = testInterfaceLookupByName, /* 0.7.0 */
- .interfaceLookupByMACString = testInterfaceLookupByMACString, /* 0.7.0 */
- .interfaceGetXMLDesc = testInterfaceGetXMLDesc, /* 0.7.0 */
- .interfaceDefineXML = testInterfaceDefineXML, /* 0.7.0 */
- .interfaceUndefine = testInterfaceUndefine, /* 0.7.0 */
- .interfaceCreate = testInterfaceCreate, /* 0.7.0 */
- .interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
- .interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
- .interfaceChangeBegin = testInterfaceChangeBegin, /* 0.9.2 */
- .interfaceChangeCommit = testInterfaceChangeCommit, /* 0.9.2 */
- .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
-};
-
-
-static virStorageDriver testStorageDriver = {
- .connectNumOfStoragePools = testConnectNumOfStoragePools, /* 0.5.0 */
- .connectListStoragePools = testConnectListStoragePools, /* 0.5.0 */
- .connectNumOfDefinedStoragePools = testConnectNumOfDefinedStoragePools, /* 0.5.0 */
- .connectListDefinedStoragePools = testConnectListDefinedStoragePools, /* 0.5.0 */
- .connectListAllStoragePools = testConnectListAllStoragePools, /* 0.10.2 */
- .connectFindStoragePoolSources = testConnectFindStoragePoolSources, /* 0.5.0 */
- .connectStoragePoolEventRegisterAny = testConnectStoragePoolEventRegisterAny, /* 2.0.0 */
- .connectStoragePoolEventDeregisterAny = testConnectStoragePoolEventDeregisterAny, /* 2.0.0 */
- .storagePoolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */
- .storagePoolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */
- .storagePoolLookupByVolume = testStoragePoolLookupByVolume, /* 0.5.0 */
- .storagePoolCreateXML = testStoragePoolCreateXML, /* 0.5.0 */
- .storagePoolDefineXML = testStoragePoolDefineXML, /* 0.5.0 */
- .storagePoolBuild = testStoragePoolBuild, /* 0.5.0 */
- .storagePoolUndefine = testStoragePoolUndefine, /* 0.5.0 */
- .storagePoolCreate = testStoragePoolCreate, /* 0.5.0 */
- .storagePoolDestroy = testStoragePoolDestroy, /* 0.5.0 */
- .storagePoolDelete = testStoragePoolDelete, /* 0.5.0 */
- .storagePoolRefresh = testStoragePoolRefresh, /* 0.5.0 */
- .storagePoolGetInfo = testStoragePoolGetInfo, /* 0.5.0 */
- .storagePoolGetXMLDesc = testStoragePoolGetXMLDesc, /* 0.5.0 */
- .storagePoolGetAutostart = testStoragePoolGetAutostart, /* 0.5.0 */
- .storagePoolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */
- .storagePoolNumOfVolumes = testStoragePoolNumOfVolumes, /* 0.5.0 */
- .storagePoolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */
- .storagePoolListAllVolumes = testStoragePoolListAllVolumes, /* 0.10.2 */
-
- .storageVolLookupByName = testStorageVolLookupByName, /* 0.5.0 */
- .storageVolLookupByKey = testStorageVolLookupByKey, /* 0.5.0 */
- .storageVolLookupByPath = testStorageVolLookupByPath, /* 0.5.0 */
- .storageVolCreateXML = testStorageVolCreateXML, /* 0.5.0 */
- .storageVolCreateXMLFrom = testStorageVolCreateXMLFrom, /* 0.6.4 */
- .storageVolDelete = testStorageVolDelete, /* 0.5.0 */
- .storageVolGetInfo = testStorageVolGetInfo, /* 0.5.0 */
- .storageVolGetXMLDesc = testStorageVolGetXMLDesc, /* 0.5.0 */
- .storageVolGetPath = testStorageVolGetPath, /* 0.5.0 */
- .storagePoolIsActive = testStoragePoolIsActive, /* 0.7.3 */
- .storagePoolIsPersistent = testStoragePoolIsPersistent, /* 0.7.3 */
-};
-
-static virNodeDeviceDriver testNodeDeviceDriver = {
- .connectNodeDeviceEventRegisterAny = testConnectNodeDeviceEventRegisterAny, /* 2.2.0 */
- .connectNodeDeviceEventDeregisterAny = testConnectNodeDeviceEventDeregisterAny, /* 2.2.0 */
- .nodeNumOfDevices = testNodeNumOfDevices, /* 0.7.2 */
- .nodeListDevices = testNodeListDevices, /* 0.7.2 */
- .nodeDeviceLookupByName = testNodeDeviceLookupByName, /* 0.7.2 */
- .nodeDeviceGetXMLDesc = testNodeDeviceGetXMLDesc, /* 0.7.2 */
- .nodeDeviceGetParent = testNodeDeviceGetParent, /* 0.7.2 */
- .nodeDeviceNumOfCaps = testNodeDeviceNumOfCaps, /* 0.7.2 */
- .nodeDeviceListCaps = testNodeDeviceListCaps, /* 0.7.2 */
- .nodeDeviceCreateXML = testNodeDeviceCreateXML, /* 0.7.3 */
- .nodeDeviceDestroy = testNodeDeviceDestroy, /* 0.7.3 */
-};
static virConnectDriver testConnectDriver = {
.hypervisorDriver = &testHypervisorDriver,
diff --git a/src/test/test_hypervisor_driver.c b/src/test/test_hypervisor_driver.c
new file mode 100644
index 0000000..96e04b6
--- /dev/null
+++ b/src/test/test_hypervisor_driver.c
@@ -0,0 +1,4152 @@
+/*
+ * test_hypervisor_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_hypervisor_driver.h"
+
+#include "test_private_driver.h"
+
+VIR_LOG_INIT("test.test_driver");
+
+static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
+
+static int
+testConnectAuthenticate(virConnectPtr conn,
+ virConnectAuthPtr auth)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+ ssize_t i;
+ char *username = NULL, *password = NULL;
+
+ if (privconn->numAuths == 0)
+ return 0;
+
+ /* Authentication is required because the test XML contains a
+ * non-empty <auth/> section. First we must ask for a username.
+ */
+ username = virAuthGetUsername(conn, auth, "test", NULL, "localhost"/*?*/);
+ if (!username) {
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed when asking for username"));
+ goto cleanup;
+ }
+
+ /* Does the username exist? */
+ for (i = 0; i < privconn->numAuths; ++i) {
+ if (STREQ(privconn->auths[i].username, username))
+ goto found_user;
+ }
+ i = -1;
+
+ found_user:
+ /* Even if we didn't find the user, we still ask for a password. */
+ if (i == -1 || privconn->auths[i].password != NULL) {
+ password = virAuthGetPassword(conn, auth, "test",
+ username, "localhost");
+ if (password == NULL) {
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed when asking for password"));
+ goto cleanup;
+ }
+ }
+
+ if (i == -1 ||
+ (password && STRNEQ(privconn->auths[i].password, password))) {
+ virReportError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed, see test XML for the correct username/password"));
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(username);
+ VIR_FREE(password);
+ return ret;
+}
+
+static int
+testParseNodeInfo(virNodeInfoPtr nodeInfo, xmlXPathContextPtr ctxt)
+{
+ char *str;
+ long l;
+ int ret;
+
+ ret = virXPathLong("string(/node/cpu/nodes[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->nodes = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu nodes value"));
+ goto error;
+ }
+
+ ret = virXPathLong("string(/node/cpu/sockets[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->sockets = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu sockets value"));
+ goto error;
+ }
+
+ ret = virXPathLong("string(/node/cpu/cores[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->cores = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu cores value"));
+ goto error;
+ }
+
+ ret = virXPathLong("string(/node/cpu/threads[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->threads = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu threads value"));
+ goto error;
+ }
+
+ nodeInfo->cpus = (nodeInfo->cores * nodeInfo->threads *
+ nodeInfo->sockets * nodeInfo->nodes);
+ ret = virXPathLong("string(/node/cpu/active[1])", ctxt, &l);
+ if (ret == 0) {
+ if (l < nodeInfo->cpus)
+ nodeInfo->cpus = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu active value"));
+ goto error;
+ }
+ ret = virXPathLong("string(/node/cpu/mhz[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->mhz = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node cpu mhz value"));
+ goto error;
+ }
+
+ str = virXPathString("string(/node/cpu/model[1])", ctxt);
+ if (str != NULL) {
+ if (virStrcpyStatic(nodeInfo->model, str) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Model %s too big for destination"), str);
+ VIR_FREE(str);
+ goto error;
+ }
+ VIR_FREE(str);
+ }
+
+ ret = virXPathLong("string(/node/memory[1])", ctxt, &l);
+ if (ret == 0) {
+ nodeInfo->memory = l;
+ } else if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid node memory value"));
+ goto error;
+ }
+
+ return 0;
+ error:
+ return -1;
+}
+
+static char *testBuildFilename(const char *relativeTo,
+ const char *filename)
+{
+ char *offset;
+ int baseLen;
+ char *ret;
+
+ if (!filename || filename[0] == '\0')
+ return NULL;
+ if (filename[0] == '/') {
+ ignore_value(VIR_STRDUP(ret, filename));
+ return ret;
+ }
+
+ offset = strrchr(relativeTo, '/');
+ if ((baseLen = (offset-relativeTo+1))) {
+ char *absFile;
+ int totalLen = baseLen + strlen(filename) + 1;
+ if (VIR_ALLOC_N(absFile, totalLen) < 0)
+ return NULL;
+ if (virStrncpy(absFile, relativeTo, baseLen, totalLen) == NULL) {
+ VIR_FREE(absFile);
+ return NULL;
+ }
+ strcat(absFile, filename);
+ return absFile;
+ } else {
+ ignore_value(VIR_STRDUP(ret, filename));
+ return ret;
+ }
+}
+
+static xmlNodePtr
+testParseXMLDocFromFile(xmlNodePtr node, const char *file, const char *type)
+{
+ xmlNodePtr ret = NULL;
+ xmlDocPtr doc = NULL;
+ char *absFile = NULL;
+ char *relFile = virXMLPropString(node, "file");
+
+ if (relFile != NULL) {
+ absFile = testBuildFilename(file, relFile);
+ VIR_FREE(relFile);
+ if (!absFile) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("resolving %s filename"), type);
+ return NULL;
+ }
+
+ if (!(doc = virXMLParse(absFile, NULL, type)))
+ goto error;
+
+ ret = xmlCopyNode(xmlDocGetRootElement(doc), 1);
+ if (!ret) {
+ virReportOOMError();
+ goto error;
+ }
+ xmlReplaceNode(node, ret);
+ xmlFreeNode(node);
+ } else {
+ ret = node;
+ }
+
+ error:
+ xmlFreeDoc(doc);
+ VIR_FREE(absFile);
+ return ret;
+}
+
+#define TEST_NAMESPACE_HREF "http://libvirt.org/schemas/domain/test/1.0"
+
+typedef struct _testDomainNamespaceDef testDomainNamespaceDef;
+typedef testDomainNamespaceDef *testDomainNamespaceDefPtr;
+struct _testDomainNamespaceDef {
+ int runstate;
+ bool transient;
+ bool hasManagedSave;
+
+ unsigned int num_snap_nodes;
+ xmlNodePtr *snap_nodes;
+};
+
+static void
+testDomainDefNamespaceFree(void *data)
+{
+ testDomainNamespaceDefPtr nsdata = data;
+ size_t i;
+
+ if (!nsdata)
+ return;
+
+ for (i = 0; i < nsdata->num_snap_nodes; i++)
+ xmlFreeNode(nsdata->snap_nodes[i]);
+
+ VIR_FREE(nsdata->snap_nodes);
+ VIR_FREE(nsdata);
+}
+
+static int
+testDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
+ xmlNodePtr root ATTRIBUTE_UNUSED,
+ xmlXPathContextPtr ctxt,
+ void **data)
+{
+ testDomainNamespaceDefPtr nsdata = NULL;
+ xmlNodePtr *nodes = NULL;
+ int tmp, n;
+ size_t i;
+ unsigned int tmpuint;
+
+ if (xmlXPathRegisterNs(ctxt, BAD_CAST "test",
+ BAD_CAST TEST_NAMESPACE_HREF) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to register xml namespace '%s'"),
+ TEST_NAMESPACE_HREF);
+ return -1;
+ }
+
+ if (VIR_ALLOC(nsdata) < 0)
+ return -1;
+
+ n = virXPathNodeSet("./test:domainsnapshot", ctxt, &nodes);
+ if (n < 0)
+ goto error;
+
+ if (n && VIR_ALLOC_N(nsdata->snap_nodes, n) < 0)
+ goto error;
+
+ for (i = 0; i < n; i++) {
+ xmlNodePtr newnode = xmlCopyNode(nodes[i], 1);
+ if (!newnode) {
+ virReportOOMError();
+ goto error;
+ }
+
+ nsdata->snap_nodes[nsdata->num_snap_nodes] = newnode;
+ nsdata->num_snap_nodes++;
+ }
+ VIR_FREE(nodes);
+
+ tmp = virXPathBoolean("boolean(./test:transient)", ctxt);
+ if (tmp == -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid transient"));
+ goto error;
+ }
+ nsdata->transient = tmp;
+
+ tmp = virXPathBoolean("boolean(./test:hasmanagedsave)", ctxt);
+ if (tmp == -1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("invalid hasmanagedsave"));
+ goto error;
+ }
+ nsdata->hasManagedSave = tmp;
+
+ tmp = virXPathUInt("string(./test:runstate)", ctxt, &tmpuint);
+ if (tmp == 0) {
+ if (tmpuint >= VIR_DOMAIN_LAST) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("runstate '%d' out of range'"), tmpuint);
+ goto error;
+ }
+ nsdata->runstate = tmpuint;
+ } else if (tmp == -1) {
+ nsdata->runstate = VIR_DOMAIN_RUNNING;
+ } else if (tmp == -2) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid runstate"));
+ goto error;
+ }
+
+ if (nsdata->transient && nsdata->runstate == VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("transient domain cannot have runstate 'shutoff'"));
+ goto error;
+ }
+ if (nsdata->hasManagedSave && nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("domain with managedsave data can only have runstate 'shutoff'"));
+ goto error;
+ }
+
+ *data = nsdata;
+ return 0;
+
+ error:
+ VIR_FREE(nodes);
+ testDomainDefNamespaceFree(nsdata);
+ return -1;
+}
+
+static int
+testParseDomainSnapshots(testDriverPtr privconn,
+ virDomainObjPtr domobj,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ size_t i;
+ int ret = -1;
+ testDomainNamespaceDefPtr nsdata = domobj->def->namespaceData;
+ xmlNodePtr *nodes = nsdata->snap_nodes;
+
+ for (i = 0; i < nsdata->num_snap_nodes; i++) {
+ virDomainSnapshotObjPtr snap;
+ virDomainSnapshotDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "domainsnapshot");
+ if (!node)
+ goto error;
+
+ def = virDomainSnapshotDefParseNode(ctxt->doc, node,
+ privconn->caps,
+ privconn->xmlopt,
+ VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
+ VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL |
+ VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
+ if (!def)
+ goto error;
+
+ if (!(snap = virDomainSnapshotAssignDef(domobj->snapshots, def))) {
+ virDomainSnapshotDefFree(def);
+ goto error;
+ }
+
+ if (def->current) {
+ if (domobj->current_snapshot) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("more than one snapshot claims to be active"));
+ goto error;
+ }
+
+ domobj->current_snapshot = snap;
+ }
+ }
+
+ if (virDomainSnapshotUpdateRelations(domobj->snapshots) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Snapshots have inconsistent relations for "
+ "domain %s"), domobj->def->name);
+ goto error;
+ }
+
+ ret = 0;
+ error:
+ return ret;
+}
+
+static void
+testDomainShutdownState(virDomainPtr domain,
+ virDomainObjPtr privdom,
+ virDomainShutoffReason reason)
+{
+ virDomainObjRemoveTransientDef(privdom);
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF, reason);
+
+ if (domain)
+ domain->id = -1;
+}
+
+/* Set up domain runtime state */
+static int
+testDomainStartState(testDriverPtr privconn,
+ virDomainObjPtr dom,
+ virDomainRunningReason reason)
+{
+ int ret = -1;
+
+ virDomainObjSetState(dom, VIR_DOMAIN_RUNNING, reason);
+ dom->def->id = virAtomicIntAdd(&privconn->nextDomID, 1);
+
+ if (virDomainObjSetDefTransient(privconn->caps,
+ privconn->xmlopt,
+ dom) < 0) {
+ goto cleanup;
+ }
+
+ dom->hasManagedSave = false;
+ ret = 0;
+ cleanup:
+ if (ret < 0)
+ testDomainShutdownState(NULL, dom, VIR_DOMAIN_SHUTOFF_FAILED);
+ return ret;
+}
+
+static char *
+testDomainGenerateIfname(virDomainDefPtr domdef)
+{
+ int maxif = 1024;
+ int ifctr;
+ size_t i;
+
+ for (ifctr = 0; ifctr < maxif; ++ifctr) {
+ char *ifname;
+ int found = 0;
+
+ if (virAsprintf(&ifname, "testnet%d", ifctr) < 0)
+ return NULL;
+
+ /* Generate network interface names */
+ for (i = 0; i < domdef->nnets; i++) {
+ if (domdef->nets[i]->ifname &&
+ STREQ(domdef->nets[i]->ifname, ifname)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return ifname;
+ VIR_FREE(ifname);
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Exceeded max iface limit %d"), maxif);
+ return NULL;
+}
+
+static int
+testDomainGenerateIfnames(virDomainDefPtr domdef)
+{
+ size_t i = 0;
+
+ for (i = 0; i < domdef->nnets; i++) {
+ char *ifname;
+ if (domdef->nets[i]->ifname)
+ continue;
+
+ ifname = testDomainGenerateIfname(domdef);
+ if (!ifname)
+ return -1;
+
+ domdef->nets[i]->ifname = ifname;
+ }
+
+ return 0;
+}
+
+static int
+testParseDomains(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virDomainObjPtr obj;
+
+ num = virXPathNodeSet("/node/domain", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virDomainDefPtr def;
+ testDomainNamespaceDefPtr nsdata;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "domain");
+ if (!node)
+ goto error;
+
+ def = virDomainDefParseNode(ctxt->doc, node,
+ privconn->caps, privconn->xmlopt,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE);
+ if (!def)
+ goto error;
+
+ if (testDomainGenerateIfnames(def) < 0 ||
+ !(obj = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ 0, NULL))) {
+ virDomainDefFree(def);
+ goto error;
+ }
+
+ if (testParseDomainSnapshots(privconn, obj, file, ctxt) < 0) {
+ virObjectUnlock(obj);
+ goto error;
+ }
+
+ nsdata = def->namespaceData;
+ obj->persistent = !nsdata->transient;
+ obj->hasManagedSave = nsdata->hasManagedSave;
+
+ if (nsdata->runstate != VIR_DOMAIN_SHUTOFF) {
+ if (testDomainStartState(privconn, obj,
+ VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+ virObjectUnlock(obj);
+ goto error;
+ }
+ } else {
+ testDomainShutdownState(NULL, obj, 0);
+ }
+ virDomainObjSetState(obj, nsdata->runstate, 0);
+
+ virObjectUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseNetworks(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virNetworkObjPtr obj;
+
+ num = virXPathNodeSet("/node/network", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virNetworkDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file, "network");
+ if (!node)
+ goto error;
+
+ def = virNetworkDefParseNode(ctxt->doc, node);
+ if (!def)
+ goto error;
+
+ if (!(obj = virNetworkAssignDef(privconn->networks, def, 0))) {
+ virNetworkDefFree(def);
+ goto error;
+ }
+
+ obj->active = 1;
+ virNetworkObjEndAPI(&obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseInterfaces(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virInterfaceObjPtr obj;
+
+ num = virXPathNodeSet("/node/interface", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virInterfaceDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "interface");
+ if (!node)
+ goto error;
+
+ def = virInterfaceDefParseNode(ctxt->doc, node);
+ if (!def)
+ goto error;
+
+ if (!(obj = virInterfaceAssignDef(&privconn->ifaces, def))) {
+ virInterfaceDefFree(def);
+ goto error;
+ }
+
+ obj->active = 1;
+ virInterfaceObjUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testOpenVolumesForPool(const char *file,
+ xmlXPathContextPtr ctxt,
+ virStoragePoolObjPtr pool,
+ int poolidx)
+{
+ char *vol_xpath;
+ size_t i;
+ int num, ret = -1;
+ xmlNodePtr *nodes = NULL;
+ virStorageVolDefPtr def = NULL;
+
+ /* Find storage volumes */
+ if (virAsprintf(&vol_xpath, "/node/pool[%d]/volume", poolidx) < 0)
+ goto error;
+
+ num = virXPathNodeSet(vol_xpath, ctxt, &nodes);
+ VIR_FREE(vol_xpath);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "volume");
+ if (!node)
+ goto error;
+
+ def = virStorageVolDefParseNode(pool->def, ctxt->doc, node, 0);
+ if (!def)
+ goto error;
+
+ if (def->target.path == NULL) {
+ if (virAsprintf(&def->target.path, "%s/%s",
+ pool->def->target.path,
+ def->name) == -1)
+ goto error;
+ }
+
+ if (!def->key && VIR_STRDUP(def->key, def->target.path) < 0)
+ goto error;
+ if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, def) < 0)
+ goto error;
+
+ pool->def->allocation += def->target.allocation;
+ pool->def->available = (pool->def->capacity -
+ pool->def->allocation);
+ def = NULL;
+ }
+
+ ret = 0;
+ error:
+ virStorageVolDefFree(def);
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseStorage(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virStoragePoolObjPtr obj;
+
+ num = virXPathNodeSet("/node/pool", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virStoragePoolDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "pool");
+ if (!node)
+ goto error;
+
+ def = virStoragePoolDefParseNode(ctxt->doc, node);
+ if (!def)
+ goto error;
+
+ if (!(obj = virStoragePoolObjAssignDef(&privconn->pools,
+ def))) {
+ virStoragePoolDefFree(def);
+ goto error;
+ }
+
+ if (testStoragePoolObjSetDefaults(obj) == -1) {
+ virStoragePoolObjUnlock(obj);
+ goto error;
+ }
+ obj->active = 1;
+
+ /* Find storage volumes */
+ if (testOpenVolumesForPool(file, ctxt, obj, i+1) < 0) {
+ virStoragePoolObjUnlock(obj);
+ goto error;
+ }
+
+ virStoragePoolObjUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseNodedevs(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+ virNodeDeviceObjPtr obj;
+
+ num = virXPathNodeSet("/node/device", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ virNodeDeviceDefPtr def;
+ xmlNodePtr node = testParseXMLDocFromFile(nodes[i], file,
+ "nodedev");
+ if (!node)
+ goto error;
+
+ def = virNodeDeviceDefParseNode(ctxt->doc, node, 0, NULL);
+ if (!def)
+ goto error;
+
+ if (!(obj = virNodeDeviceAssignDef(&privconn->devs, def))) {
+ virNodeDeviceDefFree(def);
+ goto error;
+ }
+
+ virNodeDeviceObjUnlock(obj);
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testParseAuthUsers(testDriverPtr privconn,
+ xmlXPathContextPtr ctxt)
+{
+ int num, ret = -1;
+ size_t i;
+ xmlNodePtr *nodes = NULL;
+
+ num = virXPathNodeSet("/node/auth/user", ctxt, &nodes);
+ if (num < 0)
+ goto error;
+
+ privconn->numAuths = num;
+ if (num && VIR_ALLOC_N(privconn->auths, num) < 0)
+ goto error;
+
+ for (i = 0; i < num; i++) {
+ char *username, *password;
+
+ ctxt->node = nodes[i];
+ username = virXPathString("string(.)", ctxt);
+ if (!username || STREQ(username, "")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing username in /node/auth/user field"));
+ VIR_FREE(username);
+ goto error;
+ }
+ /* This field is optional. */
+ password = virXMLPropString(nodes[i], "password");
+
+ privconn->auths[i].username = username;
+ privconn->auths[i].password = password;
+ }
+
+ ret = 0;
+ error:
+ VIR_FREE(nodes);
+ return ret;
+}
+
+static int
+testOpenParse(testDriverPtr privconn,
+ const char *file,
+ xmlXPathContextPtr ctxt)
+{
+ if (!xmlStrEqual(ctxt->node->name, BAD_CAST "node")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Root element is not 'node'"));
+ goto error;
+ }
+
+ if (testParseNodeInfo(&privconn->nodeInfo, ctxt) < 0)
+ goto error;
+ if (testParseDomains(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseNetworks(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseInterfaces(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseStorage(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseNodedevs(privconn, file, ctxt) < 0)
+ goto error;
+ if (testParseAuthUsers(privconn, ctxt) < 0)
+ goto error;
+
+ return 0;
+ error:
+ return -1;
+}
+
+static const char *defaultConnXML =
+"<node>"
+"<domain type='test'>"
+" <name>test</name>"
+" <uuid>6695eb01-f6a4-8304-79aa-97f2502e193f</uuid>"
+" <memory>8388608</memory>"
+" <currentMemory>2097152</currentMemory>"
+" <vcpu>2</vcpu>"
+" <os>"
+" <type>hvm</type>"
+" </os>"
+"</domain>"
+""
+"<network>"
+" <name>default</name>"
+" <uuid>dd8fe884-6c02-601e-7551-cca97df1c5df</uuid>"
+" <bridge name='virbr0'/>"
+" <forward/>"
+" <ip address='192.168.122.1' netmask='255.255.255.0'>"
+" <dhcp>"
+" <range start='192.168.122.2' end='192.168.122.254'/>"
+" </dhcp>"
+" </ip>"
+"</network>"
+""
+"<interface type=\"ethernet\" name=\"eth1\">"
+" <start mode=\"onboot\"/>"
+" <mac address=\"aa:bb:cc:dd:ee:ff\"/>"
+" <mtu size=\"1492\"/>"
+" <protocol family=\"ipv4\">"
+" <ip address=\"192.168.0.5\" prefix=\"24\"/>"
+" <route gateway=\"192.168.0.1\"/>"
+" </protocol>"
+"</interface>"
+""
+"<pool type='dir'>"
+" <name>default-pool</name>"
+" <uuid>dfe224cb-28fb-8dd0-c4b2-64eb3f0f4566</uuid>"
+" <target>"
+" <path>/default-pool</path>"
+" </target>"
+"</pool>"
+""
+"<device>"
+" <name>computer</name>"
+" <capability type='system'>"
+" <hardware>"
+" <vendor>Libvirt</vendor>"
+" <version>Test driver</version>"
+" <serial>123456</serial>"
+" <uuid>11111111-2222-3333-4444-555555555555</uuid>"
+" </hardware>"
+" <firmware>"
+" <vendor>Libvirt</vendor>"
+" <version>Test Driver</version>"
+" <release_date>01/22/2007</release_date>"
+" </firmware>"
+" </capability>"
+"</device>"
+"<device>"
+" <name>test-scsi-host-vport</name>"
+" <parent>computer</parent>"
+" <capability type='scsi_host'>"
+" <host>1</host>"
+" <capability type='fc_host'>"
+" <wwnn>2000000012341234</wwnn>"
+" <wwpn>1000000012341234</wwpn>"
+" </capability>"
+" <capability type='vport_ops'/>"
+" </capability>"
+"</device>"
+"</node>";
+
+static void
+testDriverFree(testDriverPtr driver)
+{
+ if (!driver)
+ return;
+
+ virObjectUnref(driver->caps);
+ virObjectUnref(driver->xmlopt);
+ virObjectUnref(driver->domains);
+ virNodeDeviceObjListFree(&driver->devs);
+ virObjectUnref(driver->networks);
+ virInterfaceObjListFree(&driver->ifaces);
+ virStoragePoolObjListFree(&driver->pools);
+ virObjectEventStateFree(driver->eventState);
+ virMutexUnlock(&driver->lock);
+ virMutexDestroy(&driver->lock);
+
+ VIR_FREE(driver);
+}
+
+static testDriverPtr
+testDriverNew(void)
+{
+ virDomainXMLNamespace ns = {
+ .parse = testDomainDefNamespaceParse,
+ .free = testDomainDefNamespaceFree,
+ };
+ testDriverPtr ret;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ if (virMutexInit(&ret->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot initialize mutex"));
+ goto error;
+ }
+
+ if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) ||
+ !(ret->eventState = virObjectEventStateNew()) ||
+ !(ret->domains = virDomainObjListNew()) ||
+ !(ret->networks = virNetworkObjListNew()))
+ goto error;
+
+ virAtomicIntSet(&ret->nextDomID, 1);
+
+ return ret;
+
+ error:
+ testDriverFree(ret);
+ return NULL;
+}
+
+#define TEST_EMULATOR "/usr/bin/test-hv"
+
+static virCapsPtr
+testBuildCapabilities(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ virCapsPtr caps;
+ virCapsGuestPtr guest;
+ int guest_types[] = { VIR_DOMAIN_OSTYPE_HVM,
+ VIR_DOMAIN_OSTYPE_XEN };
+ size_t i, j;
+
+ if ((caps = virCapabilitiesNew(VIR_ARCH_I686, false, false)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddHostFeature(caps, "pae") < 0)
+ goto error;
+ if (virCapabilitiesAddHostFeature(caps, "nonpae") < 0)
+ goto error;
+
+ if (VIR_ALLOC_N(caps->host.pagesSize, 2) < 0)
+ goto error;
+
+ caps->host.pagesSize[caps->host.nPagesSize++] = 4;
+ caps->host.pagesSize[caps->host.nPagesSize++] = 2048;
+
+ for (i = 0; i < privconn->numCells; i++) {
+ virCapsHostNUMACellCPUPtr cpu_cells;
+ virCapsHostNUMACellPageInfoPtr pages;
+ size_t nPages;
+
+ if (VIR_ALLOC_N(cpu_cells, privconn->cells[i].numCpus) < 0 ||
+ VIR_ALLOC_N(pages, caps->host.nPagesSize) < 0) {
+ VIR_FREE(cpu_cells);
+ goto error;
+ }
+
+ nPages = caps->host.nPagesSize;
+
+ memcpy(cpu_cells, privconn->cells[i].cpus,
+ sizeof(*cpu_cells) * privconn->cells[i].numCpus);
+
+ for (j = 0; j < nPages; j++)
+ pages[j].size = caps->host.pagesSize[j];
+
+ pages[0].avail = privconn->cells[i].mem / pages[0].size;
+
+ if (virCapabilitiesAddHostNUMACell(caps, i, privconn->cells[i].mem,
+ privconn->cells[i].numCpus,
+ cpu_cells, 0, NULL, nPages, pages) < 0)
+ goto error;
+ }
+
+ for (i = 0; i < ARRAY_CARDINALITY(guest_types); i++) {
+ if ((guest = virCapabilitiesAddGuest(caps,
+ guest_types[i],
+ VIR_ARCH_I686,
+ TEST_EMULATOR,
+ NULL,
+ 0,
+ NULL)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ VIR_DOMAIN_VIRT_TEST,
+ NULL,
+ NULL,
+ 0,
+ NULL) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestFeature(guest, "pae", true, true) == NULL)
+ goto error;
+ if (virCapabilitiesAddGuestFeature(guest, "nonpae", true, true) == NULL)
+ goto error;
+ }
+
+ caps->host.nsecModels = 1;
+ if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
+ goto error;
+ if (VIR_STRDUP(caps->host.secModels[0].model, "testSecurity") < 0)
+ goto error;
+
+ if (VIR_STRDUP(caps->host.secModels[0].doi, "") < 0)
+ goto error;
+
+ return caps;
+
+ error:
+ virObjectUnref(caps);
+ return NULL;
+}
+
+#define TEST_MODEL "i686"
+
+static const virNodeInfo defaultNodeInfo = {
+ TEST_MODEL,
+ 1024*1024*3, /* 3 GB */
+ 16,
+ 1400,
+ 2,
+ 2,
+ 2,
+ 2,
+};
+
+static virMutex defaultLock = VIR_MUTEX_INITIALIZER;
+
+static testDriverPtr defaultConn;
+static int defaultConnections;
+
+/* Simultaneous test:///default connections should share the same
+ * common state (among other things, this allows testing event
+ * detection in one connection for an action caused in another). */
+static int
+testOpenDefault(virConnectPtr conn)
+{
+ int u;
+ testDriverPtr privconn = NULL;
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+
+ virMutexLock(&defaultLock);
+ if (defaultConnections++) {
+ conn->privateData = defaultConn;
+ virMutexUnlock(&defaultLock);
+ return VIR_DRV_OPEN_SUCCESS;
+ }
+
+ if (!(privconn = testDriverNew()))
+ goto error;
+
+ conn->privateData = privconn;
+
+ memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+ /* Numa setup */
+ privconn->numCells = 2;
+ for (u = 0; u < privconn->numCells; ++u) {
+ privconn->cells[u].numCpus = 8;
+ privconn->cells[u].mem = (u + 1) * 2048 * 1024;
+ privconn->cells[u].freeMem = (u + 1) * 1024 * 1024;
+ }
+ for (u = 0; u < 16; u++) {
+ virBitmapPtr siblings = virBitmapNew(16);
+ if (!siblings)
+ goto error;
+ ignore_value(virBitmapSetBit(siblings, u));
+ privconn->cells[u / 8].cpus[(u % 8)].id = u;
+ privconn->cells[u / 8].cpus[(u % 8)].socket_id = u / 8;
+ privconn->cells[u / 8].cpus[(u % 8)].core_id = u % 8;
+ privconn->cells[u / 8].cpus[(u % 8)].siblings = siblings;
+ }
+
+ if (!(privconn->caps = testBuildCapabilities(conn)))
+ goto error;
+
+ if (!(doc = virXMLParseStringCtxt(defaultConnXML,
+ _("(test driver)"), &ctxt)))
+ goto error;
+
+ if (testOpenParse(privconn, NULL, ctxt) < 0)
+ goto error;
+
+ defaultConn = privconn;
+
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ virMutexUnlock(&defaultLock);
+
+ return VIR_DRV_OPEN_SUCCESS;
+
+ error:
+ testDriverFree(privconn);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ conn->privateData = NULL;
+ defaultConnections--;
+ virMutexUnlock(&defaultLock);
+ return VIR_DRV_OPEN_ERROR;
+}
+
+static int
+testOpenFromFile(virConnectPtr conn, const char *file)
+{
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ testDriverPtr privconn;
+
+ if (!(privconn = testDriverNew()))
+ return VIR_DRV_OPEN_ERROR;
+
+ testDriverLock(privconn);
+ conn->privateData = privconn;
+
+ if (!(privconn->caps = testBuildCapabilities(conn)))
+ goto error;
+
+ if (!(doc = virXMLParseFileCtxt(file, &ctxt)))
+ goto error;
+
+ privconn->numCells = 0;
+ memmove(&privconn->nodeInfo, &defaultNodeInfo, sizeof(defaultNodeInfo));
+
+ if (testOpenParse(privconn, file, ctxt) < 0)
+ goto error;
+
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ testDriverUnlock(privconn);
+
+ return 0;
+
+ error:
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(doc);
+ testDriverFree(privconn);
+ conn->privateData = NULL;
+ return VIR_DRV_OPEN_ERROR;
+}
+
+static virDrvOpenStatus testConnectOpen(virConnectPtr conn,
+ virConnectAuthPtr auth,
+ virConfPtr conf ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ int ret;
+
+ virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
+
+ if (!conn->uri)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "test"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* Remote driver should handle these. */
+ if (conn->uri->server)
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* From this point on, the connection is for us. */
+ if (!conn->uri->path
+ || conn->uri->path[0] == '\0'
+ || (conn->uri->path[0] == '/' && conn->uri->path[1] == '\0')) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("testOpen: supply a path or use test:///default"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ if (STREQ(conn->uri->path, "/default"))
+ ret = testOpenDefault(conn);
+ else
+ ret = testOpenFromFile(conn,
+ conn->uri->path);
+
+ if (ret != VIR_DRV_OPEN_SUCCESS)
+ return ret;
+
+ /* Fake authentication. */
+ if (testConnectAuthenticate(conn, auth) < 0)
+ return VIR_DRV_OPEN_ERROR;
+
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int testConnectClose(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ bool dflt = false;
+
+ if (privconn == defaultConn) {
+ dflt = true;
+ virMutexLock(&defaultLock);
+ if (--defaultConnections) {
+ virMutexUnlock(&defaultLock);
+ return 0;
+ }
+ }
+
+ testDriverLock(privconn);
+ testDriverFree(privconn);
+
+ if (dflt) {
+ defaultConn = NULL;
+ virMutexUnlock(&defaultLock);
+ }
+
+ conn->privateData = NULL;
+ return 0;
+}
+
+static int testConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned long *hvVer)
+{
+ *hvVer = 2;
+ return 0;
+}
+
+static char *testConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return virGetHostname();
+}
+
+static int testConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *type ATTRIBUTE_UNUSED)
+{
+ return 32;
+}
+
+int testNodeGetInfo(virConnectPtr conn,
+ virNodeInfoPtr info)
+{
+ testDriverPtr privconn = conn->privateData;
+ testDriverLock(privconn);
+ memcpy(info, &privconn->nodeInfo, sizeof(virNodeInfo));
+ testDriverUnlock(privconn);
+ return 0;
+}
+
+#define TEST_NB_CPU_STATS 4
+
+static int
+testNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
+ int cpuNum ATTRIBUTE_UNUSED,
+ virNodeCPUStatsPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ size_t i = 0;
+
+ virCheckFlags(0, -1);
+
+ if (params == NULL) {
+ *nparams = TEST_NB_CPU_STATS;
+ return 0;
+ }
+
+ for (i = 0; i < *nparams && i < 4; i++) {
+ switch (i) {
+ case 0:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_USER, 9797400000) < 0)
+ return -1;
+ break;
+ case 1:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_KERNEL, 34678723400000) < 0)
+ return -1;
+ break;
+ case 2:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_IDLE, 87264900000) < 0)
+ return -1;
+ break;
+ case 3:
+ if (virHostCPUStatsAssign(¶ms[i],
+ VIR_NODE_CPU_STATS_IOWAIT, 763600000) < 0)
+ return -1;
+ break;
+ }
+ }
+
+ *nparams = i;
+ return 0;
+}
+
+static unsigned long long
+testNodeGetFreeMemory(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ unsigned int freeMem = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+
+ for (i = 0; i < privconn->numCells; i++)
+ freeMem += privconn->cells[i].freeMem;
+
+ testDriverUnlock(privconn);
+ return freeMem;
+}
+
+static int
+testNodeGetFreePages(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned int npages,
+ unsigned int *pages ATTRIBUTE_UNUSED,
+ int startCell ATTRIBUTE_UNUSED,
+ unsigned int cellCount,
+ unsigned long long *counts,
+ unsigned int flags)
+{
+ size_t i = 0, j = 0;
+ int x = 6;
+
+ virCheckFlags(0, -1);
+
+ for (i = 0; i < cellCount; i++) {
+ for (j = 0; j < npages; j++) {
+ x = x * 2 + 7;
+ counts[(i * npages) + j] = x;
+ }
+ }
+
+ return 0;
+}
+
+static char *testConnectGetCapabilities(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ char *xml;
+ testDriverLock(privconn);
+ xml = virCapabilitiesFormatXML(privconn->caps);
+ testDriverUnlock(privconn);
+ return xml;
+}
+
+static char *
+testConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ char *ret;
+ const char *sysinfo = "<sysinfo type='smbios'>\n"
+ " <bios>\n"
+ " <entry name='vendor'>LENOVO</entry>\n"
+ " <entry name='version'>G4ETA1WW (2.61 )</entry>\n"
+ " <entry name='date'>05/07/2014</entry>\n"
+ " <entry name='release'>2.61</entry>\n"
+ " </bios>\n"
+ "</sysinfo>\n";
+
+ virCheckFlags(0, NULL);
+
+ ignore_value(VIR_STRDUP(ret, sysinfo));
+ return ret;
+}
+
+static const char *
+testConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return "TEST";
+}
+
+static int testConnectListDomains(virConnectPtr conn,
+ int *ids,
+ int maxids)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ return virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
+ NULL, NULL);
+}
+
+static int testConnectNumOfDomains(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int count;
+
+ testDriverLock(privconn);
+ count = virDomainObjListNumOfDomains(privconn->domains, true, NULL, NULL);
+ testDriverUnlock(privconn);
+
+ return count;
+}
+
+static int testConnectListAllDomains(virConnectPtr conn,
+ virDomainPtr **domains,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
+
+ return virDomainObjListExport(privconn->domains, conn, domains,
+ NULL, flags);
+}
+
+static virDomainPtr
+testDomainCreateXML(virConnectPtr conn, const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainDefPtr def;
+ virDomainObjPtr dom = NULL;
+ virObjectEventPtr event = NULL;
+ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+
+ virCheckFlags(VIR_DOMAIN_START_VALIDATE, NULL);
+
+ if (flags & VIR_DOMAIN_START_VALIDATE)
+ parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
+
+ testDriverLock(privconn);
+ if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ parse_flags)) == NULL)
+ goto cleanup;
+
+ if (testDomainGenerateIfnames(def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+ VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+ NULL)))
+ goto cleanup;
+ def = NULL;
+
+ if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
+ if (!dom->persistent) {
+ virDomainObjListRemove(privconn->domains, dom);
+ dom = NULL;
+ }
+ goto cleanup;
+ }
+
+ event = virDomainEventLifecycleNewFromObj(dom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ testObjectEventQueue(privconn, event);
+ virDomainDefFree(def);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+
+static virDomainPtr testDomainLookupByID(virConnectPtr conn,
+ int id)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainObjPtr dom;
+
+ if (!(dom = virDomainObjListFindByID(privconn->domains, id))) {
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ return ret;
+}
+
+static virDomainPtr testDomainLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainObjPtr dom;
+
+ if (!(dom = virDomainObjListFindByUUID(privconn->domains, uuid))) {
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ return ret;
+}
+
+static virDomainPtr testDomainLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainObjPtr dom;
+
+ if (!(dom = virDomainObjListFindByName(privconn->domains, name))) {
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ virDomainObjEndAPI(&dom);
+ return ret;
+}
+
+static virDomainObjPtr
+testDomObjFromDomain(virDomainPtr domain)
+{
+ virDomainObjPtr vm;
+ testDriverPtr driver = domain->conn->privateData;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ vm = virDomainObjListFindByUUIDRef(driver->domains, domain->uuid);
+ if (!vm) {
+ virUUIDFormat(domain->uuid, uuidstr);
+ virReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s' (%s)"),
+ uuidstr, domain->name);
+ }
+
+ return vm;
+}
+
+static int testDomainSuspend(virDomainPtr domain)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+ int state;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ state = virDomainObjGetState(privdom, NULL);
+ if (state == VIR_DOMAIN_SHUTOFF || state == VIR_DOMAIN_PAUSED) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not running"),
+ domain->name);
+ goto cleanup;
+ }
+
+ virDomainObjSetState(privdom, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainResume(virDomainPtr domain)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_PAUSED) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("domain '%s' not paused"),
+ domain->name);
+ goto cleanup;
+ }
+
+ virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_UNPAUSED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainShutdownFlags(virDomainPtr domain,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("domain '%s' not running"), domain->name);
+ goto cleanup;
+ }
+
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainShutdown(virDomainPtr domain)
+{
+ return testDomainShutdownFlags(domain, 0);
+}
+
+/* Similar behaviour as shutdown */
+static int testDomainReboot(virDomainPtr domain,
+ unsigned int action ATTRIBUTE_UNUSED)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTDOWN,
+ VIR_DOMAIN_SHUTDOWN_USER);
+
+ switch (privdom->def->onReboot) {
+ case VIR_DOMAIN_LIFECYCLE_DESTROY:
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ break;
+
+ case VIR_DOMAIN_LIFECYCLE_RESTART:
+ virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_BOOTED);
+ break;
+
+ case VIR_DOMAIN_LIFECYCLE_PRESERVE:
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ break;
+
+ case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME:
+ virDomainObjSetState(privdom, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_BOOTED);
+ break;
+
+ default:
+ virDomainObjSetState(privdom, VIR_DOMAIN_SHUTOFF,
+ VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ break;
+ }
+
+ if (virDomainObjGetState(privdom, NULL) == VIR_DOMAIN_SHUTOFF) {
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+ }
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainDestroy(virDomainPtr domain)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_DESTROYED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static char *
+testDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+ char *ret;
+
+ ignore_value(VIR_STRDUP(ret, "linux"));
+ return ret;
+}
+
+static unsigned long long
+testDomainGetMaxMemory(virDomainPtr domain)
+{
+ virDomainObjPtr privdom;
+ unsigned long long ret = 0;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return 0;
+
+ ret = virDomainDefGetMemoryTotal(privdom->def);
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainSetMaxMemory(virDomainPtr domain,
+ unsigned long memory)
+{
+ virDomainObjPtr privdom;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ /* XXX validate not over host memory wrt to other domains */
+ virDomainDefSetMemoryTotal(privdom->def, memory);
+
+ virDomainObjEndAPI(&privdom);
+ return 0;
+}
+
+static int testDomainSetMemory(virDomainPtr domain,
+ unsigned long memory)
+{
+ virDomainObjPtr privdom;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (memory > virDomainDefGetMemoryTotal(privdom->def)) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privdom->def->mem.cur_balloon = memory;
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainGetInfo(virDomainPtr domain,
+ virDomainInfoPtr info)
+{
+ struct timeval tv;
+ virDomainObjPtr privdom;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("getting time of day"));
+ goto cleanup;
+ }
+
+ info->state = virDomainObjGetState(privdom, NULL);
+ info->memory = privdom->def->mem.cur_balloon;
+ info->maxMem = virDomainDefGetMemoryTotal(privdom->def);
+ info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
+ info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll));
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetState(virDomainPtr domain,
+ int *state,
+ int *reason,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+
+ virCheckFlags(0, -1);
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ *state = virDomainObjGetState(privdom, reason);
+
+ virDomainObjEndAPI(&privdom);
+
+ return 0;
+}
+
+#define TEST_SAVE_MAGIC "TestGuestMagic"
+
+static int
+testDomainSaveFlags(virDomainPtr domain, const char *path,
+ const char *dxml, unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ char *xml = NULL;
+ int fd = -1;
+ int len;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+ if (dxml) {
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+ _("xml modification unsupported"));
+ return -1;
+ }
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ xml = virDomainDefFormat(privdom->def, privconn->caps,
+ VIR_DOMAIN_DEF_FORMAT_SECURE);
+
+ if (xml == NULL) {
+ virReportSystemError(errno,
+ _("saving domain '%s' failed to allocate space for metadata"),
+ domain->name);
+ goto cleanup;
+ }
+
+ if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': open failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ len = strlen(xml);
+ if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ if (safewrite(fd, xml, len) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+
+ if (VIR_CLOSE(fd) < 0) {
+ virReportSystemError(errno,
+ _("saving domain '%s' to '%s': write failed"),
+ domain->name, path);
+ goto cleanup;
+ }
+ fd = -1;
+
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_SAVED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(xml);
+
+ /* Don't report failure in close or unlink, because
+ * in either case we're already in a failure scenario
+ * and have reported a earlier error */
+ if (ret != 0) {
+ VIR_FORCE_CLOSE(fd);
+ unlink(path);
+ }
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int
+testDomainSave(virDomainPtr domain,
+ const char *path)
+{
+ return testDomainSaveFlags(domain, path, NULL, 0);
+}
+
+static int
+testDomainRestoreFlags(virConnectPtr conn,
+ const char *path,
+ const char *dxml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ char *xml = NULL;
+ char magic[15];
+ int fd = -1;
+ int len;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr dom = NULL;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+ if (dxml) {
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+ _("xml modification unsupported"));
+ return -1;
+ }
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ virReportSystemError(errno,
+ _("cannot read domain image '%s'"),
+ path);
+ goto cleanup;
+ }
+ if (saferead(fd, magic, sizeof(magic)) != sizeof(magic)) {
+ virReportSystemError(errno,
+ _("incomplete save header in '%s'"),
+ path);
+ goto cleanup;
+ }
+ if (memcmp(magic, TEST_SAVE_MAGIC, sizeof(magic))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("mismatched header magic"));
+ goto cleanup;
+ }
+ if (saferead(fd, (char*)&len, sizeof(len)) != sizeof(len)) {
+ virReportSystemError(errno,
+ _("failed to read metadata length in '%s'"),
+ path);
+ goto cleanup;
+ }
+ if (len < 1 || len > 8192) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("length of metadata out of range"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC_N(xml, len+1) < 0)
+ goto cleanup;
+ if (saferead(fd, xml, len) != len) {
+ virReportSystemError(errno,
+ _("incomplete metadata in '%s'"), path);
+ goto cleanup;
+ }
+ xml[len] = '\0';
+
+ def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE);
+ if (!def)
+ goto cleanup;
+
+ if (testDomainGenerateIfnames(def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+ VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+ NULL)))
+ goto cleanup;
+ def = NULL;
+
+ if (testDomainStartState(privconn, dom, VIR_DOMAIN_RUNNING_RESTORED) < 0) {
+ if (!dom->persistent) {
+ virDomainObjListRemove(privconn->domains, dom);
+ dom = NULL;
+ }
+ goto cleanup;
+ }
+
+ event = virDomainEventLifecycleNewFromObj(dom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_RESTORED);
+ ret = 0;
+
+ cleanup:
+ virDomainDefFree(def);
+ VIR_FREE(xml);
+ VIR_FORCE_CLOSE(fd);
+ if (dom)
+ virObjectUnlock(dom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int
+testDomainRestore(virConnectPtr conn,
+ const char *path)
+{
+ return testDomainRestoreFlags(conn, path, NULL, 0);
+}
+
+static int testDomainCoreDumpWithFormat(virDomainPtr domain,
+ const char *to,
+ unsigned int dumpformat,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ int fd = -1;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DUMP_CRASH, -1);
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+ virReportSystemError(errno,
+ _("domain '%s' coredump: failed to open %s"),
+ domain->name, to);
+ goto cleanup;
+ }
+ if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
+ virReportSystemError(errno,
+ _("domain '%s' coredump: failed to write header to %s"),
+ domain->name, to);
+ goto cleanup;
+ }
+ if (VIR_CLOSE(fd) < 0) {
+ virReportSystemError(errno,
+ _("domain '%s' coredump: write failed: %s"),
+ domain->name, to);
+ goto cleanup;
+ }
+
+ /* we don't support non-raw formats in test driver */
+ if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("kdump-compressed format is not supported here"));
+ goto cleanup;
+ }
+
+ if (flags & VIR_DUMP_CRASH) {
+ testDomainShutdownState(domain, privdom, VIR_DOMAIN_SHUTOFF_CRASHED);
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_CRASHED);
+ if (!privdom->persistent)
+ virDomainObjListRemove(privconn->domains, privdom);
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+
+static int
+testDomainCoreDump(virDomainPtr domain,
+ const char *to,
+ unsigned int flags)
+{
+ return testDomainCoreDumpWithFormat(domain, to,
+ VIR_DOMAIN_CORE_DUMP_FORMAT_RAW, flags);
+}
+
+static int
+testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
+ unsigned int flags)
+{
+ testDriverPtr driver = domain->conn->privateData;
+ virDomainObjPtr privdom = NULL;
+ virDomainDefPtr def;
+ virDomainDefPtr persistentDef;
+ int ret = -1, maxvcpus;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+ if ((maxvcpus = testConnectGetMaxVcpus(domain->conn, NULL)) < 0)
+ return -1;
+
+ if (nrCpus > maxvcpus) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested cpu amount exceeds maximum supported amount "
+ "(%d > %d)"), nrCpus, maxvcpus);
+ return -1;
+ }
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
+ goto cleanup;
+
+ if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested cpu amount exceeds maximum (%d > %d)"),
+ nrCpus, virDomainDefGetVcpusMax(def));
+ goto cleanup;
+ }
+
+ if (persistentDef &&
+ !(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
+ virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested cpu amount exceeds maximum (%d > %d)"),
+ nrCpus, virDomainDefGetVcpusMax(persistentDef));
+ goto cleanup;
+ }
+
+ if (def &&
+ virDomainDefSetVcpus(def, nrCpus) < 0)
+ goto cleanup;
+
+ if (persistentDef) {
+ if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
+ if (virDomainDefSetVcpusMax(persistentDef, nrCpus,
+ driver->xmlopt) < 0)
+ goto cleanup;
+ } else {
+ if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainSetVcpus(virDomainPtr domain, unsigned int nrCpus)
+{
+ return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_AFFECT_LIVE);
+}
+
+static int testDomainGetVcpus(virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+ unsigned char *cpumaps,
+ int maplen)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virDomainDefPtr def;
+ size_t i;
+ int maxcpu, hostcpus;
+ int ret = -1;
+ struct timeval tv;
+ unsigned long long statbase;
+ virBitmapPtr allcpumap = NULL;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (!virDomainObjIsActive(privdom)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot list vcpus for an inactive domain"));
+ goto cleanup;
+ }
+
+ def = privdom->def;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(errno,
+ "%s", _("getting time of day"));
+ goto cleanup;
+ }
+
+ statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+
+ hostcpus = VIR_NODEINFO_MAXCPUS(privconn->nodeInfo);
+ maxcpu = maplen * 8;
+ if (maxcpu > hostcpus)
+ maxcpu = hostcpus;
+
+ if (!(allcpumap = virBitmapNew(hostcpus)))
+ goto cleanup;
+
+ virBitmapSetAll(allcpumap);
+
+ /* Clamp to actual number of vcpus */
+ if (maxinfo > virDomainDefGetVcpus(privdom->def))
+ maxinfo = virDomainDefGetVcpus(privdom->def);
+
+ memset(info, 0, sizeof(*info) * maxinfo);
+ memset(cpumaps, 0, maxinfo * maplen);
+
+ for (i = 0; i < maxinfo; i++) {
+ virDomainVcpuDefPtr vcpu = virDomainDefGetVcpu(def, i);
+ virBitmapPtr bitmap = NULL;
+
+ if (!vcpu->online)
+ continue;
+
+ if (vcpu->cpumask)
+ bitmap = vcpu->cpumask;
+ else if (def->cpumask)
+ bitmap = def->cpumask;
+ else
+ bitmap = allcpumap;
+
+ if (cpumaps)
+ virBitmapToDataBuf(bitmap, VIR_GET_CPUMAP(cpumaps, maplen, i), maplen);
+
+ info[i].number = i;
+ info[i].state = VIR_VCPU_RUNNING;
+ info[i].cpu = virBitmapLastSetBit(bitmap);
+
+ /* Fake an increasing cpu time value */
+ info[i].cpuTime = statbase / 10;
+ }
+
+ ret = maxinfo;
+ cleanup:
+ virBitmapFree(allcpumap);
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainPinVcpu(virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+ int maplen)
+{
+ virDomainVcpuDefPtr vcpuinfo;
+ virDomainObjPtr privdom;
+ virDomainDefPtr def;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ def = privdom->def;
+
+ if (!virDomainObjIsActive(privdom)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot pin vcpus on an inactive domain"));
+ goto cleanup;
+ }
+
+ if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu)) ||
+ !vcpuinfo->online) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("requested vcpu '%d' is not present in the domain"),
+ vcpu);
+ goto cleanup;
+ }
+
+ virBitmapFree(vcpuinfo->cpumask);
+
+ if (!(vcpuinfo->cpumask = virBitmapNewData(cpumap, maplen)))
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetVcpuPinInfo(virDomainPtr dom,
+ int ncpumaps,
+ unsigned char *cpumaps,
+ int maplen,
+ unsigned int flags)
+{
+ testDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr privdom;
+ virDomainDefPtr def;
+ int ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(privdom, flags)))
+ goto cleanup;
+
+ ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps,
+ VIR_NODEINFO_MAXCPUS(driver->nodeInfo),
+ NULL);
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainDefPtr def;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (!(def = virDomainObjGetOneDef(vm, flags)))
+ goto cleanup;
+
+ if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
+ ret = virDomainDefGetVcpusMax(def);
+ else
+ ret = virDomainDefGetVcpus(def);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainGetMaxVcpus(virDomainPtr domain)
+{
+ return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_VCPU_MAXIMUM));
+}
+
+static char *testDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainDefPtr def;
+ virDomainObjPtr privdom;
+ char *ret = NULL;
+
+ /* Flags checked by virDomainDefFormat */
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return NULL;
+
+ def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
+ privdom->newDef ? privdom->newDef : privdom->def;
+
+ ret = virDomainDefFormat(def, privconn->caps,
+ virDomainDefFormatConvertXMLFlags(flags));
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testConnectNumOfDefinedDomains(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ return virDomainObjListNumOfDomains(privconn->domains, false, NULL, NULL);
+}
+
+static int testConnectListDefinedDomains(virConnectPtr conn,
+ char **const names,
+ int maxnames)
+{
+
+ testDriverPtr privconn = conn->privateData;
+
+ memset(names, 0, sizeof(*names)*maxnames);
+ return virDomainObjListGetInactiveNames(privconn->domains, names, maxnames,
+ NULL, NULL);
+}
+
+static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (virDomainObjGetState(privdom, NULL) != VIR_DOMAIN_SHUTOFF) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Domain '%s' is already running"), domain->name);
+ goto cleanup;
+ }
+
+ if (testDomainStartState(privconn, privdom,
+ VIR_DOMAIN_RUNNING_BOOTED) < 0)
+ goto cleanup;
+ domain->id = privdom->def->id;
+
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testDomainCreate(virDomainPtr domain)
+{
+ return testDomainCreateWithFlags(domain, 0);
+}
+
+static virDomainPtr testDomainDefineXMLFlags(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virDomainPtr ret = NULL;
+ virDomainDefPtr def;
+ virDomainObjPtr dom = NULL;
+ virObjectEventPtr event = NULL;
+ virDomainDefPtr oldDef = NULL;
+ unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
+
+ virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
+
+ if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
+ parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
+
+ if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ parse_flags)) == NULL)
+ goto cleanup;
+
+ if (testDomainGenerateIfnames(def) < 0)
+ goto cleanup;
+ if (!(dom = virDomainObjListAdd(privconn->domains,
+ def,
+ privconn->xmlopt,
+ 0,
+ &oldDef)))
+ goto cleanup;
+ def = NULL;
+ dom->persistent = 1;
+
+ event = virDomainEventLifecycleNewFromObj(dom,
+ VIR_DOMAIN_EVENT_DEFINED,
+ !oldDef ?
+ VIR_DOMAIN_EVENT_DEFINED_ADDED :
+ VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+
+ ret = virGetDomain(conn, dom->def->name, dom->def->uuid);
+ if (ret)
+ ret->id = dom->def->id;
+
+ cleanup:
+ virDomainDefFree(def);
+ virDomainDefFree(oldDef);
+ if (dom)
+ virObjectUnlock(dom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static virDomainPtr
+testDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ return testDomainDefineXMLFlags(conn, xml, 0);
+}
+
+static int testDomainUndefineFlags(virDomainPtr domain,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ virObjectEventPtr event = NULL;
+ int nsnapshots;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
+ VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
+
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (privdom->hasManagedSave &&
+ !(flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Refusing to undefine while domain managed "
+ "save image exists"));
+ goto cleanup;
+ }
+
+ /* Requiring an inactive VM is part of the documented API for
+ * UNDEFINE_SNAPSHOTS_METADATA
+ */
+ if (!virDomainObjIsActive(privdom) &&
+ (nsnapshots = virDomainSnapshotObjListNum(privdom->snapshots,
+ NULL, 0))) {
+ if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("cannot delete inactive domain with %d "
+ "snapshots"),
+ nsnapshots);
+ goto cleanup;
+ }
+
+ /* There isn't actually anything to do, we are just emulating qemu
+ * behavior here. */
+ }
+
+ event = virDomainEventLifecycleNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+ privdom->hasManagedSave = false;
+
+ if (virDomainObjIsActive(privdom))
+ privdom->persistent = 0;
+ else
+ virDomainObjListRemove(privconn->domains, privdom);
+
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ testObjectEventQueue(privconn, event);
+ return ret;
+}
+
+static int testDomainUndefine(virDomainPtr domain)
+{
+ return testDomainUndefineFlags(domain, 0);
+}
+
+static int testDomainGetAutostart(virDomainPtr domain,
+ int *autostart)
+{
+ virDomainObjPtr privdom;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ *autostart = privdom->autostart;
+
+ virDomainObjEndAPI(&privdom);
+ return 0;
+}
+
+
+static int testDomainSetAutostart(virDomainPtr domain,
+ int autostart)
+{
+ virDomainObjPtr privdom;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ privdom->autostart = autostart ? 1 : 0;
+
+ virDomainObjEndAPI(&privdom);
+ return 0;
+}
+
+static char *testDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
+ int *nparams)
+{
+ char *type = NULL;
+
+ if (nparams)
+ *nparams = 1;
+
+ ignore_value(VIR_STRDUP(type, "fair"));
+
+ return type;
+}
+
+static int
+testDomainGetSchedulerParametersFlags(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ if (virTypedParameterAssign(params, VIR_DOMAIN_SCHEDULER_WEIGHT,
+ VIR_TYPED_PARAM_UINT, 50) < 0)
+ goto cleanup;
+ /* XXX */
+ /*params[0].value.ui = privdom->weight;*/
+
+ *nparams = 1;
+ ret = 0;
+
+ cleanup:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainGetSchedulerParameters(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int *nparams)
+{
+ return testDomainGetSchedulerParametersFlags(domain, params, nparams, 0);
+}
+
+static int
+testDomainSetSchedulerParametersFlags(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+ int ret = -1;
+ size_t i;
+
+ virCheckFlags(0, -1);
+ if (virTypedParamsValidate(params, nparams,
+ VIR_DOMAIN_SCHEDULER_WEIGHT,
+ VIR_TYPED_PARAM_UINT,
+ NULL) < 0)
+ return -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ for (i = 0; i < nparams; i++) {
+ if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
+ /* XXX */
+ /*privdom->weight = params[i].value.ui;*/
+ }
+ }
+
+ ret = 0;
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testDomainSetSchedulerParameters(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int nparams)
+{
+ return testDomainSetSchedulerParametersFlags(domain, params, nparams, 0);
+}
+
+static int testDomainBlockStats(virDomainPtr domain,
+ const char *path,
+ virDomainBlockStatsPtr stats)
+{
+ virDomainObjPtr privdom;
+ struct timeval tv;
+ unsigned long long statbase;
+ int ret = -1;
+
+ if (!*path) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("summary statistics are not supported yet"));
+ return ret;
+ }
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return ret;
+
+ if (virDomainDiskIndexByName(privdom->def, path, false) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path: %s"), path);
+ goto error;
+ }
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(errno,
+ "%s", _("getting time of day"));
+ goto error;
+ }
+
+ /* No significance to these numbers, just enough to mix it up*/
+ statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+ stats->rd_req = statbase / 10;
+ stats->rd_bytes = statbase / 20;
+ stats->wr_req = statbase / 30;
+ stats->wr_bytes = statbase / 40;
+ stats->errs = tv.tv_sec / 2;
+
+ ret = 0;
+ error:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainInterfaceStats(virDomainPtr domain,
+ const char *path,
+ virDomainInterfaceStatsPtr stats)
+{
+ virDomainObjPtr privdom;
+ struct timeval tv;
+ unsigned long long statbase;
+ size_t i;
+ int found = 0, ret = -1;
+
+ if (!(privdom = testDomObjFromDomain(domain)))
+ return -1;
+
+ for (i = 0; i < privdom->def->nnets; i++) {
+ if (privdom->def->nets[i]->ifname &&
+ STREQ(privdom->def->nets[i]->ifname, path)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path, '%s' is not a known interface"), path);
+ goto error;
+ }
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ virReportSystemError(errno,
+ "%s", _("getting time of day"));
+ goto error;
+ }
+
+ /* No significance to these numbers, just enough to mix it up*/
+ statbase = (tv.tv_sec * 1000UL * 1000UL) + tv.tv_usec;
+ stats->rx_bytes = statbase / 10;
+ stats->rx_packets = statbase / 100;
+ stats->rx_errs = tv.tv_sec / 1;
+ stats->rx_drop = tv.tv_sec / 2;
+ stats->tx_bytes = statbase / 20;
+ stats->tx_packets = statbase / 110;
+ stats->tx_errs = tv.tv_sec / 3;
+ stats->tx_drop = tv.tv_sec / 4;
+
+ ret = 0;
+ error:
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testNodeGetCellsFreeMemory(virConnectPtr conn,
+ unsigned long long *freemems,
+ int startCell, int maxCells)
+{
+ testDriverPtr privconn = conn->privateData;
+ int cell;
+ size_t i;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ if (startCell > privconn->numCells) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("Range exceeds available cells"));
+ goto cleanup;
+ }
+
+ for (cell = startCell, i = 0;
+ (cell < privconn->numCells && i < maxCells);
+ ++cell, ++i) {
+ freemems[i] = privconn->cells[cell].mem;
+ }
+ ret = i;
+
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+/* Domain event implementations */
+static int
+testConnectDomainEventRegister(virConnectPtr conn,
+ virConnectDomainEventCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virDomainEventStateRegister(conn, driver->eventState,
+ callback, opaque, freecb) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int
+testConnectDomainEventDeregister(virConnectPtr conn,
+ virConnectDomainEventCallback callback)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virDomainEventStateDeregister(conn, driver->eventState,
+ callback) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int
+testConnectDomainEventRegisterAny(virConnectPtr conn,
+ virDomainPtr dom,
+ int eventID,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virDomainEventStateRegisterID(conn, driver->eventState,
+ dom, eventID,
+ callback, opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectDomainEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int testConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int testConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static int testConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static int testDomainIsActive(virDomainPtr dom)
+{
+ virDomainObjPtr obj;
+ int ret;
+
+ if (!(obj = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = virDomainObjIsActive(obj);
+ virDomainObjEndAPI(&obj);
+ return ret;
+}
+
+static int testDomainIsPersistent(virDomainPtr dom)
+{
+ virDomainObjPtr obj;
+ int ret;
+
+ if (!(obj = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = obj->persistent;
+
+ virDomainObjEndAPI(&obj);
+ return ret;
+}
+
+static int testDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+static int
+testNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
+ unsigned char **cpumap,
+ unsigned int *online,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (cpumap) {
+ if (VIR_ALLOC_N(*cpumap, 1) < 0)
+ return -1;
+ *cpumap[0] = 0x15;
+ }
+
+ if (online)
+ *online = 3;
+
+ return 8;
+}
+
+static char *
+testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED,
+ virStreamPtr st,
+ unsigned int screen ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (VIR_STRDUP(ret, "image/png") < 0)
+ return NULL;
+
+ if (virFDStreamOpenFile(st, PKGDATADIR "/libvirtLogo.png", 0, 0, O_RDONLY) < 0)
+ VIR_FREE(ret);
+
+ return ret;
+}
+
+static char *testDomainGetMetadata(virDomainPtr dom,
+ int type,
+ const char *uri,
+ unsigned int flags)
+{
+ virDomainObjPtr privdom;
+ char *ret;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, NULL);
+
+ if (!(privdom = testDomObjFromDomain(dom)))
+ return NULL;
+
+ ret = virDomainObjGetMetadata(privdom, type, uri, flags);
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int testDomainSetMetadata(virDomainPtr dom,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags)
+{
+ testDriverPtr privconn = dom->conn->privateData;
+ virDomainObjPtr privdom;
+ int ret;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ if (!(privdom = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
+ privconn->caps, privconn->xmlopt,
+ NULL, NULL, flags);
+
+ virDomainObjEndAPI(&privdom);
+ return ret;
+}
+
+static int
+testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *arch,
+ char ***models,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+ return cpuGetModels(arch, models);
+}
+
+static int
+testDomainManagedSave(virDomainPtr dom, unsigned int flags)
+{
+ testDriverPtr privconn = dom->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virObjectEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
+ VIR_DOMAIN_SAVE_RUNNING |
+ VIR_DOMAIN_SAVE_PAUSED, -1);
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot do managed save for transient domain"));
+ goto cleanup;
+ }
+
+ testDomainShutdownState(dom, vm, VIR_DOMAIN_SHUTOFF_SAVED);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+ vm->hasManagedSave = true;
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ testObjectEventQueue(privconn, event);
+
+ return ret;
+}
+
+static int
+testDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
+{
+ virDomainObjPtr vm;
+ int ret;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ ret = vm->hasManagedSave;
+
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
+{
+ virDomainObjPtr vm;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromDomain(dom)))
+ return -1;
+
+ vm->hasManagedSave = false;
+
+ virDomainObjEndAPI(&vm);
+ return 0;
+}
+
+/*
+ * Snapshot APIs
+ */
+
+static virDomainSnapshotObjPtr
+testSnapObjFromName(virDomainObjPtr vm,
+ const char *name)
+{
+ virDomainSnapshotObjPtr snap = NULL;
+ snap = virDomainSnapshotFindByName(vm->snapshots, name);
+ if (!snap)
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+ _("no domain snapshot with matching name '%s'"),
+ name);
+ return snap;
+}
+
+static virDomainSnapshotObjPtr
+testSnapObjFromSnapshot(virDomainObjPtr vm,
+ virDomainSnapshotPtr snapshot)
+{
+ return testSnapObjFromName(vm, snapshot->name);
+}
+
+static virDomainObjPtr
+testDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
+{
+ return testDomObjFromDomain(snapshot->domain);
+}
+
+static int
+testDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int n;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
+
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotListNames(virDomainPtr domain,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int n;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
+ flags);
+
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainListAllSnapshots(virDomainPtr domain,
+ virDomainSnapshotPtr **snaps,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int n;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
+
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
+ char **names,
+ int nameslen,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
+ flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static int
+testDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
+ virDomainSnapshotPtr **snaps,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ int n = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+ VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
+ flags);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return n;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotLookupByName(virDomainPtr domain,
+ const char *name,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotPtr snapshot = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!(snap = testSnapObjFromName(vm, name)))
+ goto cleanup;
+
+ snapshot = virGetDomainSnapshot(domain, snap->def->name);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return snapshot;
+}
+
+static int
+testDomainHasCurrentSnapshot(virDomainPtr domain,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ int ret;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return -1;
+
+ ret = (vm->current_snapshot != NULL);
+
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotPtr parent = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return NULL;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ if (!snap->def->parent) {
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
+ _("snapshot '%s' does not have a parent"),
+ snap->def->name);
+ goto cleanup;
+ }
+
+ parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return parent;
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotCurrent(virDomainPtr domain,
+ unsigned int flags)
+{
+ virDomainObjPtr vm;
+ virDomainSnapshotPtr snapshot = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ return NULL;
+
+ if (!vm->current_snapshot) {
+ virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
+ _("the domain does not have a current snapshot"));
+ goto cleanup;
+ }
+
+ snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return snapshot;
+}
+
+static char *
+testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ char *xml = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ testDriverPtr privconn = snapshot->domain->conn->privateData;
+
+ virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return NULL;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+ xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return xml;
+}
+
+static int
+testDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int ret;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ ret = (vm->current_snapshot &&
+ STREQ(snapshot->name, vm->current_snapshot->def->name));
+
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+
+static int
+testDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!testSnapObjFromSnapshot(vm, snapshot))
+ goto cleanup;
+
+ ret = 1;
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainSnapshotAlignDisks(virDomainObjPtr vm,
+ virDomainSnapshotDefPtr def,
+ unsigned int flags)
+{
+ int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ bool align_match = true;
+
+ if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
+ align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+ align_match = false;
+ if (virDomainObjIsActive(vm))
+ def->state = VIR_DOMAIN_DISK_SNAPSHOT;
+ else
+ def->state = VIR_DOMAIN_SHUTOFF;
+ def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
+ } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
+ def->state = virDomainObjGetState(vm, NULL);
+ align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
+ align_match = false;
+ } else {
+ def->state = virDomainObjGetState(vm, NULL);
+ def->memory = def->state == VIR_DOMAIN_SHUTOFF ?
+ VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
+ VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
+ }
+
+ return virDomainSnapshotAlignDisks(def, align_location, align_match);
+}
+
+static virDomainSnapshotPtr
+testDomainSnapshotCreateXML(virDomainPtr domain,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ testDriverPtr privconn = domain->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotDefPtr def = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotPtr snapshot = NULL;
+ virObjectEventPtr event = NULL;
+ char *xml = NULL;
+ bool update_current = true;
+ bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
+ unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
+
+ /*
+ * DISK_ONLY: Not implemented yet
+ * REUSE_EXT: Not implemented yet
+ *
+ * NO_METADATA: Explicitly not implemented
+ *
+ * REDEFINE + CURRENT: Implemented
+ * HALT: Implemented
+ * QUIESCE: Nothing to do
+ * ATOMIC: Nothing to do
+ * LIVE: Nothing to do
+ */
+ virCheckFlags(
+ VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
+ VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
+ VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
+ VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
+ VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
+ VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
+
+ if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)))
+ update_current = false;
+ if (redefine)
+ parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
+
+ if (!(vm = testDomObjFromDomain(domain)))
+ goto cleanup;
+
+ if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot halt after transient domain snapshot"));
+ goto cleanup;
+ }
+
+ if (!(def = virDomainSnapshotDefParseString(xmlDesc,
+ privconn->caps,
+ privconn->xmlopt,
+ parse_flags)))
+ goto cleanup;
+
+ if (redefine) {
+ if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
+ &update_current, flags) < 0)
+ goto cleanup;
+ } else {
+ if (!(def->dom = virDomainDefCopy(vm->def,
+ privconn->caps,
+ privconn->xmlopt,
+ true)))
+ goto cleanup;
+
+ if (testDomainSnapshotAlignDisks(vm, def, flags) < 0)
+ goto cleanup;
+ }
+
+ if (!snap) {
+ if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
+ goto cleanup;
+ def = NULL;
+ }
+
+ if (!redefine) {
+ if (vm->current_snapshot &&
+ (VIR_STRDUP(snap->def->parent,
+ vm->current_snapshot->def->name) < 0))
+ goto cleanup;
+
+ if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) &&
+ virDomainObjIsActive(vm)) {
+ testDomainShutdownState(domain, vm,
+ VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+ event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+ }
+ }
+
+ snapshot = virGetDomainSnapshot(domain, snap->def->name);
+ cleanup:
+ VIR_FREE(xml);
+ if (vm) {
+ if (snapshot) {
+ virDomainSnapshotObjPtr other;
+ if (update_current)
+ vm->current_snapshot = snap;
+ other = virDomainSnapshotFindByName(vm->snapshots,
+ snap->def->parent);
+ snap->parent = other;
+ other->nchildren++;
+ snap->sibling = other->first_child;
+ other->first_child = snap;
+ }
+ virDomainObjEndAPI(&vm);
+ }
+ testObjectEventQueue(privconn, event);
+ virDomainSnapshotDefFree(def);
+ return snapshot;
+}
+
+
+typedef struct _testSnapRemoveData testSnapRemoveData;
+typedef testSnapRemoveData *testSnapRemoveDataPtr;
+struct _testSnapRemoveData {
+ virDomainObjPtr vm;
+ bool current;
+};
+
+static int
+testDomainSnapshotDiscardAll(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ virDomainSnapshotObjPtr snap = payload;
+ testSnapRemoveDataPtr curr = data;
+
+ if (snap->def->current)
+ curr->current = true;
+ virDomainSnapshotObjListRemove(curr->vm->snapshots, snap);
+ return 0;
+}
+
+typedef struct _testSnapReparentData testSnapReparentData;
+typedef testSnapReparentData *testSnapReparentDataPtr;
+struct _testSnapReparentData {
+ virDomainSnapshotObjPtr parent;
+ virDomainObjPtr vm;
+ int err;
+ virDomainSnapshotObjPtr last;
+};
+
+static int
+testDomainSnapshotReparentChildren(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ virDomainSnapshotObjPtr snap = payload;
+ testSnapReparentDataPtr rep = data;
+
+ if (rep->err < 0)
+ return 0;
+
+ VIR_FREE(snap->def->parent);
+ snap->parent = rep->parent;
+
+ if (rep->parent->def &&
+ VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
+ rep->err = -1;
+ return 0;
+ }
+
+ if (!snap->sibling)
+ rep->last = snap;
+ return 0;
+}
+
+static int
+testDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ virDomainSnapshotObjPtr parentsnap = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+ VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
+ VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
+ testSnapRemoveData rem;
+ rem.vm = vm;
+ rem.current = false;
+ virDomainSnapshotForEachDescendant(snap,
+ testDomainSnapshotDiscardAll,
+ &rem);
+ if (rem.current) {
+ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)
+ snap->def->current = true;
+ vm->current_snapshot = snap;
+ }
+ } else if (snap->nchildren) {
+ testSnapReparentData rep;
+ rep.parent = snap->parent;
+ rep.vm = vm;
+ rep.err = 0;
+ rep.last = NULL;
+ virDomainSnapshotForEachChild(snap,
+ testDomainSnapshotReparentChildren,
+ &rep);
+ if (rep.err < 0)
+ goto cleanup;
+
+ /* Can't modify siblings during ForEachChild, so do it now. */
+ snap->parent->nchildren += snap->nchildren;
+ rep.last->sibling = snap->parent->first_child;
+ snap->parent->first_child = snap->first_child;
+ }
+
+ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
+ snap->nchildren = 0;
+ snap->first_child = NULL;
+ } else {
+ virDomainSnapshotDropParent(snap);
+ if (snap == vm->current_snapshot) {
+ if (snap->def->parent) {
+ parentsnap = virDomainSnapshotFindByName(vm->snapshots,
+ snap->def->parent);
+ if (!parentsnap) {
+ VIR_WARN("missing parent snapshot matching name '%s'",
+ snap->def->parent);
+ } else {
+ parentsnap->def->current = true;
+ }
+ }
+ vm->current_snapshot = parentsnap;
+ }
+ virDomainSnapshotObjListRemove(vm->snapshots, snap);
+ }
+
+ ret = 0;
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
+ unsigned int flags)
+{
+ testDriverPtr privconn = snapshot->domain->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ virDomainSnapshotObjPtr snap = NULL;
+ virObjectEventPtr event = NULL;
+ virObjectEventPtr event2 = NULL;
+ virDomainDefPtr config = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
+ VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
+
+ /* We have the following transitions, which create the following events:
+ * 1. inactive -> inactive: none
+ * 2. inactive -> running: EVENT_STARTED
+ * 3. inactive -> paused: EVENT_STARTED, EVENT_PAUSED
+ * 4. running -> inactive: EVENT_STOPPED
+ * 5. running -> running: none
+ * 6. running -> paused: EVENT_PAUSED
+ * 7. paused -> inactive: EVENT_STOPPED
+ * 8. paused -> running: EVENT_RESUMED
+ * 9. paused -> paused: none
+ * Also, several transitions occur even if we fail partway through,
+ * and use of FORCE can cause multiple transitions.
+ */
+
+ if (!(vm = testDomObjFromSnapshot(snapshot)))
+ return -1;
+
+ if (!(snap = testSnapObjFromSnapshot(vm, snapshot)))
+ goto cleanup;
+
+ if (!vm->persistent &&
+ snap->def->state != VIR_DOMAIN_RUNNING &&
+ snap->def->state != VIR_DOMAIN_PAUSED &&
+ (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("transient domain needs to request run or pause "
+ "to revert to inactive snapshot"));
+ goto cleanup;
+ }
+
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
+ if (!snap->def->dom) {
+ virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
+ _("snapshot '%s' lacks domain '%s' rollback info"),
+ snap->def->name, vm->def->name);
+ goto cleanup;
+ }
+ if (virDomainObjIsActive(vm) &&
+ !(snap->def->state == VIR_DOMAIN_RUNNING
+ || snap->def->state == VIR_DOMAIN_PAUSED) &&
+ (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
+ virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
+ _("must respawn guest to start inactive snapshot"));
+ goto cleanup;
+ }
+ }
+
+
+ if (vm->current_snapshot) {
+ vm->current_snapshot->def->current = false;
+ vm->current_snapshot = NULL;
+ }
+
+ snap->def->current = true;
+ config = virDomainDefCopy(snap->def->dom,
+ privconn->caps, privconn->xmlopt, true);
+ if (!config)
+ goto cleanup;
+
+ if (snap->def->state == VIR_DOMAIN_RUNNING ||
+ snap->def->state == VIR_DOMAIN_PAUSED) {
+ /* Transitions 2, 3, 5, 6, 8, 9 */
+ bool was_running = false;
+ bool was_stopped = false;
+
+ if (virDomainObjIsActive(vm)) {
+ /* Transitions 5, 6, 8, 9 */
+ /* Check for ABI compatibility. */
+ if (!virDomainDefCheckABIStability(vm->def, config)) {
+ virErrorPtr err = virGetLastError();
+
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
+ /* Re-spawn error using correct category. */
+ if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
+ virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
+ err->str2);
+ goto cleanup;
+ }
+
+ virResetError(err);
+ testDomainShutdownState(snapshot->domain, vm,
+ VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+ testObjectEventQueue(privconn, event);
+ goto load;
+ }
+
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ /* Transitions 5, 6 */
+ was_running = true;
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+ /* Create an event now in case the restore fails, so
+ * that user will be alerted that they are now paused.
+ * If restore later succeeds, we might replace this. */
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+ }
+ virDomainObjAssignDef(vm, config, false, NULL);
+
+ } else {
+ /* Transitions 2, 3 */
+ load:
+ was_stopped = true;
+ virDomainObjAssignDef(vm, config, false, NULL);
+ if (testDomainStartState(privconn, vm,
+ VIR_DOMAIN_RUNNING_FROM_SNAPSHOT) < 0)
+ goto cleanup;
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ }
+
+ /* Touch up domain state. */
+ if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
+ (snap->def->state == VIR_DOMAIN_PAUSED ||
+ (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
+ /* Transitions 3, 6, 9 */
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+ VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
+ if (was_stopped) {
+ /* Transition 3, use event as-is and add event2 */
+ event2 = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+ } /* else transition 6 and 9 use event as-is */
+ } else {
+ /* Transitions 2, 5, 8 */
+ virObjectUnref(event);
+ event = NULL;
+
+ if (was_stopped) {
+ /* Transition 2 */
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ } else if (was_running) {
+ /* Transition 8 */
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED);
+ }
+ }
+ } else {
+ /* Transitions 1, 4, 7 */
+ virDomainObjAssignDef(vm, config, false, NULL);
+
+ if (virDomainObjIsActive(vm)) {
+ /* Transitions 4, 7 */
+ testDomainShutdownState(snapshot->domain, vm,
+ VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
+ }
+
+ if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
+ VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
+ /* Flush first event, now do transition 2 or 3 */
+ bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
+
+ testObjectEventQueue(privconn, event);
+ event = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
+ if (paused) {
+ event2 = virDomainEventLifecycleNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
+ }
+ }
+ }
+
+ vm->current_snapshot = snap;
+ ret = 0;
+ cleanup:
+ if (event) {
+ testObjectEventQueue(privconn, event);
+ testObjectEventQueue(privconn, event2);
+ } else {
+ virObjectUnref(event2);
+ }
+ virDomainObjEndAPI(&vm);
+
+ return ret;
+}
+
+static char *
+testConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char **xmlCPUs,
+ unsigned int ncpus,
+ unsigned int flags)
+{
+ char *cpu;
+
+ virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
+
+ cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
+
+ return cpu;
+}
+
+virHypervisorDriver testHypervisorDriver = {
+ .name = "Test",
+ .connectOpen = testConnectOpen, /* 0.1.1 */
+ .connectClose = testConnectClose, /* 0.1.1 */
+ .connectGetVersion = testConnectGetVersion, /* 0.1.1 */
+ .connectGetHostname = testConnectGetHostname, /* 0.6.3 */
+ .connectGetMaxVcpus = testConnectGetMaxVcpus, /* 0.3.2 */
+ .nodeGetInfo = testNodeGetInfo, /* 0.1.1 */
+ .nodeGetCPUStats = testNodeGetCPUStats, /* 2.3.0 */
+ .nodeGetFreeMemory = testNodeGetFreeMemory, /* 2.3.0 */
+ .nodeGetFreePages = testNodeGetFreePages, /* 2.3.0 */
+ .connectGetCapabilities = testConnectGetCapabilities, /* 0.2.1 */
+ .connectGetSysinfo = testConnectGetSysinfo, /* 2.3.0 */
+ .connectGetType = testConnectGetType, /* 2.3.0 */
+ .connectListDomains = testConnectListDomains, /* 0.1.1 */
+ .connectNumOfDomains = testConnectNumOfDomains, /* 0.1.1 */
+ .connectListAllDomains = testConnectListAllDomains, /* 0.9.13 */
+ .domainCreateXML = testDomainCreateXML, /* 0.1.4 */
+ .domainLookupByID = testDomainLookupByID, /* 0.1.1 */
+ .domainLookupByUUID = testDomainLookupByUUID, /* 0.1.1 */
+ .domainLookupByName = testDomainLookupByName, /* 0.1.1 */
+ .domainSuspend = testDomainSuspend, /* 0.1.1 */
+ .domainResume = testDomainResume, /* 0.1.1 */
+ .domainShutdown = testDomainShutdown, /* 0.1.1 */
+ .domainShutdownFlags = testDomainShutdownFlags, /* 0.9.10 */
+ .domainReboot = testDomainReboot, /* 0.1.1 */
+ .domainDestroy = testDomainDestroy, /* 0.1.1 */
+ .domainGetOSType = testDomainGetOSType, /* 0.1.9 */
+ .domainGetMaxMemory = testDomainGetMaxMemory, /* 0.1.4 */
+ .domainSetMaxMemory = testDomainSetMaxMemory, /* 0.1.1 */
+ .domainSetMemory = testDomainSetMemory, /* 0.1.4 */
+ .domainGetInfo = testDomainGetInfo, /* 0.1.1 */
+ .domainGetState = testDomainGetState, /* 0.9.2 */
+ .domainSave = testDomainSave, /* 0.3.2 */
+ .domainSaveFlags = testDomainSaveFlags, /* 0.9.4 */
+ .domainRestore = testDomainRestore, /* 0.3.2 */
+ .domainRestoreFlags = testDomainRestoreFlags, /* 0.9.4 */
+ .domainCoreDump = testDomainCoreDump, /* 0.3.2 */
+ .domainCoreDumpWithFormat = testDomainCoreDumpWithFormat, /* 1.2.3 */
+ .domainSetVcpus = testDomainSetVcpus, /* 0.1.4 */
+ .domainSetVcpusFlags = testDomainSetVcpusFlags, /* 0.8.5 */
+ .domainGetVcpusFlags = testDomainGetVcpusFlags, /* 0.8.5 */
+ .domainPinVcpu = testDomainPinVcpu, /* 0.7.3 */
+ .domainGetVcpus = testDomainGetVcpus, /* 0.7.3 */
+ .domainGetVcpuPinInfo = testDomainGetVcpuPinInfo, /* 1.2.18 */
+ .domainGetMaxVcpus = testDomainGetMaxVcpus, /* 0.7.3 */
+ .domainGetXMLDesc = testDomainGetXMLDesc, /* 0.1.4 */
+ .connectListDefinedDomains = testConnectListDefinedDomains, /* 0.1.11 */
+ .connectNumOfDefinedDomains = testConnectNumOfDefinedDomains, /* 0.1.11 */
+ .domainCreate = testDomainCreate, /* 0.1.11 */
+ .domainCreateWithFlags = testDomainCreateWithFlags, /* 0.8.2 */
+ .domainDefineXML = testDomainDefineXML, /* 0.1.11 */
+ .domainDefineXMLFlags = testDomainDefineXMLFlags, /* 1.2.12 */
+ .domainUndefine = testDomainUndefine, /* 0.1.11 */
+ .domainUndefineFlags = testDomainUndefineFlags, /* 0.9.4 */
+ .domainGetAutostart = testDomainGetAutostart, /* 0.3.2 */
+ .domainSetAutostart = testDomainSetAutostart, /* 0.3.2 */
+ .domainGetSchedulerType = testDomainGetSchedulerType, /* 0.3.2 */
+ .domainGetSchedulerParameters = testDomainGetSchedulerParameters, /* 0.3.2 */
+ .domainGetSchedulerParametersFlags = testDomainGetSchedulerParametersFlags, /* 0.9.2 */
+ .domainSetSchedulerParameters = testDomainSetSchedulerParameters, /* 0.3.2 */
+ .domainSetSchedulerParametersFlags = testDomainSetSchedulerParametersFlags, /* 0.9.2 */
+ .domainBlockStats = testDomainBlockStats, /* 0.7.0 */
+ .domainInterfaceStats = testDomainInterfaceStats, /* 0.7.0 */
+ .nodeGetCellsFreeMemory = testNodeGetCellsFreeMemory, /* 0.4.2 */
+ .connectDomainEventRegister = testConnectDomainEventRegister, /* 0.6.0 */
+ .connectDomainEventDeregister = testConnectDomainEventDeregister, /* 0.6.0 */
+ .connectIsEncrypted = testConnectIsEncrypted, /* 0.7.3 */
+ .connectIsSecure = testConnectIsSecure, /* 0.7.3 */
+ .domainIsActive = testDomainIsActive, /* 0.7.3 */
+ .domainIsPersistent = testDomainIsPersistent, /* 0.7.3 */
+ .domainIsUpdated = testDomainIsUpdated, /* 0.8.6 */
+ .connectDomainEventRegisterAny = testConnectDomainEventRegisterAny, /* 0.8.0 */
+ .connectDomainEventDeregisterAny = testConnectDomainEventDeregisterAny, /* 0.8.0 */
+ .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
+ .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
+ .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
+ .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
+ .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
+ .connectGetCPUModelNames = testConnectGetCPUModelNames, /* 1.1.3 */
+ .domainManagedSave = testDomainManagedSave, /* 1.1.4 */
+ .domainHasManagedSaveImage = testDomainHasManagedSaveImage, /* 1.1.4 */
+ .domainManagedSaveRemove = testDomainManagedSaveRemove, /* 1.1.4 */
+
+ .domainSnapshotNum = testDomainSnapshotNum, /* 1.1.4 */
+ .domainSnapshotListNames = testDomainSnapshotListNames, /* 1.1.4 */
+ .domainListAllSnapshots = testDomainListAllSnapshots, /* 1.1.4 */
+ .domainSnapshotGetXMLDesc = testDomainSnapshotGetXMLDesc, /* 1.1.4 */
+ .domainSnapshotNumChildren = testDomainSnapshotNumChildren, /* 1.1.4 */
+ .domainSnapshotListChildrenNames = testDomainSnapshotListChildrenNames, /* 1.1.4 */
+ .domainSnapshotListAllChildren = testDomainSnapshotListAllChildren, /* 1.1.4 */
+ .domainSnapshotLookupByName = testDomainSnapshotLookupByName, /* 1.1.4 */
+ .domainHasCurrentSnapshot = testDomainHasCurrentSnapshot, /* 1.1.4 */
+ .domainSnapshotGetParent = testDomainSnapshotGetParent, /* 1.1.4 */
+ .domainSnapshotCurrent = testDomainSnapshotCurrent, /* 1.1.4 */
+ .domainSnapshotIsCurrent = testDomainSnapshotIsCurrent, /* 1.1.4 */
+ .domainSnapshotHasMetadata = testDomainSnapshotHasMetadata, /* 1.1.4 */
+ .domainSnapshotCreateXML = testDomainSnapshotCreateXML, /* 1.1.4 */
+ .domainRevertToSnapshot = testDomainRevertToSnapshot, /* 1.1.4 */
+ .domainSnapshotDelete = testDomainSnapshotDelete, /* 1.1.4 */
+
+ .connectBaselineCPU = testConnectBaselineCPU, /* 1.2.0 */
+};
diff --git a/src/test/test_hypervisor_driver.h b/src/test/test_hypervisor_driver.h
new file mode 100644
index 0000000..ffca9c2
--- /dev/null
+++ b/src/test/test_hypervisor_driver.h
@@ -0,0 +1 @@
+extern virHypervisorDriver testHypervisorDriver;
diff --git a/src/test/test_interface_driver.c b/src/test/test_interface_driver.c
new file mode 100644
index 0000000..a749b9f
--- /dev/null
+++ b/src/test/test_interface_driver.c
@@ -0,0 +1,487 @@
+/*
+ * test_interface_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_interface_driver.h"
+
+#include "test_private_driver.h"
+
+static int testConnectNumOfInterfaces(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ int count = 0;
+
+ testDriverLock(privconn);
+ for (i = 0; (i < privconn->ifaces.count); i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (virInterfaceObjIsActive(privconn->ifaces.objs[i]))
+ count++;
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+ return count;
+}
+
+static int testConnectListInterfaces(virConnectPtr conn, char **const names, int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
+ if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ goto error;
+ }
+ }
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static int testConnectNumOfDefinedInterfaces(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ int count = 0;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->ifaces.count; i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (!virInterfaceObjIsActive(privconn->ifaces.objs[i]))
+ count++;
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+ return count;
+}
+
+static int testConnectListDefinedInterfaces(virConnectPtr conn, char **const names, int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; (i < privconn->ifaces.count) && (n < nnames); i++) {
+ virInterfaceObjLock(privconn->ifaces.objs[i]);
+ if (!virInterfaceObjIsActive(privconn->ifaces.objs[i])) {
+ if (VIR_STRDUP(names[n++], privconn->ifaces.objs[i]->def->name) < 0) {
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ goto error;
+ }
+ }
+ virInterfaceObjUnlock(privconn->ifaces.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static virInterfacePtr testInterfaceLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virInterfaceObjPtr iface;
+ virInterfacePtr ret = NULL;
+
+ testDriverLock(privconn);
+ iface = virInterfaceFindByName(&privconn->ifaces, name);
+ testDriverUnlock(privconn);
+
+ if (iface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+ if (iface)
+ virInterfaceObjUnlock(iface);
+ return ret;
+}
+
+static virInterfacePtr testInterfaceLookupByMACString(virConnectPtr conn,
+ const char *mac)
+{
+ testDriverPtr privconn = conn->privateData;
+ virInterfaceObjPtr iface;
+ int ifacect;
+ virInterfacePtr ret = NULL;
+
+ testDriverLock(privconn);
+ ifacect = virInterfaceFindByMACString(&privconn->ifaces, mac, &iface, 1);
+ testDriverUnlock(privconn);
+
+ if (ifacect == 0) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ if (ifacect > 1) {
+ virReportError(VIR_ERR_MULTIPLE_INTERFACES, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+ if (iface)
+ virInterfaceObjUnlock(iface);
+ return ret;
+}
+
+static char *testInterfaceGetXMLDesc(virInterfacePtr iface,
+ unsigned int flags)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+ testDriverUnlock(privconn);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virInterfaceDefFormat(privinterface->def);
+
+ cleanup:
+ if (privinterface)
+ virInterfaceObjUnlock(privinterface);
+ return ret;
+}
+
+static virInterfacePtr testInterfaceDefineXML(virConnectPtr conn, const char *xmlStr,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virInterfaceDefPtr def;
+ virInterfaceObjPtr iface = NULL;
+ virInterfacePtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ if ((def = virInterfaceDefParseString(xmlStr)) == NULL)
+ goto cleanup;
+
+ if ((iface = virInterfaceAssignDef(&privconn->ifaces, def)) == NULL)
+ goto cleanup;
+ def = NULL;
+
+ ret = virGetInterface(conn, iface->def->name, iface->def->mac);
+
+ cleanup:
+ virInterfaceDefFree(def);
+ if (iface)
+ virInterfaceObjUnlock(iface);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceUndefine(virInterfacePtr iface)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ virInterfaceRemove(&privconn->ifaces,
+ privinterface);
+ ret = 0;
+
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceCreate(virInterfacePtr iface,
+ unsigned int flags)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ if (privinterface->active != 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, NULL);
+ goto cleanup;
+ }
+
+ privinterface->active = 1;
+ ret = 0;
+
+ cleanup:
+ if (privinterface)
+ virInterfaceObjUnlock(privinterface);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceDestroy(virInterfacePtr iface,
+ unsigned int flags)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr privinterface;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privinterface = virInterfaceFindByName(&privconn->ifaces,
+ iface->name);
+
+ if (privinterface == NULL) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+
+ if (privinterface->active == 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID, NULL);
+ goto cleanup;
+ }
+
+ privinterface->active = 0;
+ ret = 0;
+
+ cleanup:
+ if (privinterface)
+ virInterfaceObjUnlock(privinterface);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceIsActive(virInterfacePtr iface)
+{
+ testDriverPtr privconn = iface->conn->privateData;
+ virInterfaceObjPtr obj;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ obj = virInterfaceFindByName(&privconn->ifaces, iface->name);
+ testDriverUnlock(privconn);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_INTERFACE, NULL);
+ goto cleanup;
+ }
+ ret = virInterfaceObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virInterfaceObjUnlock(obj);
+ return ret;
+}
+
+static int testInterfaceChangeBegin(virConnectPtr conn,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ if (privconn->transaction_running) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("there is another transaction running."));
+ goto cleanup;
+ }
+
+ privconn->transaction_running = true;
+
+ if (virInterfaceObjListClone(&privconn->ifaces,
+ &privconn->backupIfaces) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int testInterfaceChangeCommit(virConnectPtr conn,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+
+ if (!privconn->transaction_running) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("no transaction running, "
+ "nothing to be committed."));
+ goto cleanup;
+ }
+
+ virInterfaceObjListFree(&privconn->backupIfaces);
+ privconn->transaction_running = false;
+
+ ret = 0;
+
+ cleanup:
+ testDriverUnlock(privconn);
+
+ return ret;
+}
+
+static int testInterfaceChangeRollback(virConnectPtr conn,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+
+ if (!privconn->transaction_running) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("no transaction running, "
+ "nothing to rollback."));
+ goto cleanup;
+ }
+
+ virInterfaceObjListFree(&privconn->ifaces);
+ privconn->ifaces.count = privconn->backupIfaces.count;
+ privconn->ifaces.objs = privconn->backupIfaces.objs;
+ privconn->backupIfaces.count = 0;
+ privconn->backupIfaces.objs = NULL;
+
+ privconn->transaction_running = false;
+
+ ret = 0;
+
+ cleanup:
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+virInterfaceDriver testInterfaceDriver = {
+ .connectNumOfInterfaces = testConnectNumOfInterfaces, /* 0.7.0 */
+ .connectListInterfaces = testConnectListInterfaces, /* 0.7.0 */
+ .connectNumOfDefinedInterfaces = testConnectNumOfDefinedInterfaces, /* 0.7.0 */
+ .connectListDefinedInterfaces = testConnectListDefinedInterfaces, /* 0.7.0 */
+ .interfaceLookupByName = testInterfaceLookupByName, /* 0.7.0 */
+ .interfaceLookupByMACString = testInterfaceLookupByMACString, /* 0.7.0 */
+ .interfaceGetXMLDesc = testInterfaceGetXMLDesc, /* 0.7.0 */
+ .interfaceDefineXML = testInterfaceDefineXML, /* 0.7.0 */
+ .interfaceUndefine = testInterfaceUndefine, /* 0.7.0 */
+ .interfaceCreate = testInterfaceCreate, /* 0.7.0 */
+ .interfaceDestroy = testInterfaceDestroy, /* 0.7.0 */
+ .interfaceIsActive = testInterfaceIsActive, /* 0.7.3 */
+ .interfaceChangeBegin = testInterfaceChangeBegin, /* 0.9.2 */
+ .interfaceChangeCommit = testInterfaceChangeCommit, /* 0.9.2 */
+ .interfaceChangeRollback = testInterfaceChangeRollback, /* 0.9.2 */
+};
diff --git a/src/test/test_interface_driver.h b/src/test/test_interface_driver.h
new file mode 100644
index 0000000..34cdc43
--- /dev/null
+++ b/src/test/test_interface_driver.h
@@ -0,0 +1 @@
+extern virInterfaceDriver testInterfaceDriver;
diff --git a/src/test/test_network_driver.c b/src/test/test_network_driver.c
new file mode 100644
index 0000000..34b30fb
--- /dev/null
+++ b/src/test/test_network_driver.c
@@ -0,0 +1,540 @@
+/*
+ * test_network_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+#include "test_network_driver.h"
+
+#include "test_private_driver.h"
+
+static int testConnectNumOfNetworks(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numActive;
+
+ numActive = virNetworkObjListNumOfNetworks(privconn->networks,
+ true, NULL, conn);
+ return numActive;
+}
+
+static int testConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
+ testDriverPtr privconn = conn->privateData;
+ int n;
+
+ n = virNetworkObjListGetNames(privconn->networks,
+ true, names, nnames, NULL, conn);
+ return n;
+}
+
+static int testConnectNumOfDefinedNetworks(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numInactive;
+
+ numInactive = virNetworkObjListNumOfNetworks(privconn->networks,
+ false, NULL, conn);
+ return numInactive;
+}
+
+static int testConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
+ testDriverPtr privconn = conn->privateData;
+ int n;
+
+ n = virNetworkObjListGetNames(privconn->networks,
+ false, names, nnames, NULL, conn);
+ return n;
+}
+
+static int
+testConnectListAllNetworks(virConnectPtr conn,
+ virNetworkPtr **nets,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+
+ virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);
+
+ return virNetworkObjListExport(conn, privconn->networks, nets, NULL, flags);
+}
+
+static int testNetworkIsActive(virNetworkPtr net)
+{
+ testDriverPtr privconn = net->conn->privateData;
+ virNetworkObjPtr obj;
+ int ret = -1;
+
+ obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+ ret = virNetworkObjIsActive(obj);
+
+ cleanup:
+ virNetworkObjEndAPI(&obj);
+ return ret;
+}
+
+static int testNetworkIsPersistent(virNetworkPtr net)
+{
+ testDriverPtr privconn = net->conn->privateData;
+ virNetworkObjPtr obj;
+ int ret = -1;
+
+ obj = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+ ret = obj->persistent;
+
+ cleanup:
+ virNetworkObjEndAPI(&obj);
+ return ret;
+}
+
+
+static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkDefPtr def;
+ virNetworkObjPtr net = NULL;
+ virNetworkPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ if ((def = virNetworkDefParseString(xml)) == NULL)
+ goto cleanup;
+
+ if (!(net = virNetworkAssignDef(privconn->networks, def,
+ VIR_NETWORK_OBJ_LIST_ADD_LIVE |
+ VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
+ goto cleanup;
+ def = NULL;
+ net->active = 1;
+
+ event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
+ VIR_NETWORK_EVENT_STARTED,
+ 0);
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkDefFree(def);
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static
+virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkDefPtr def;
+ virNetworkObjPtr net = NULL;
+ virNetworkPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ if ((def = virNetworkDefParseString(xml)) == NULL)
+ goto cleanup;
+
+ if (!(net = virNetworkAssignDef(privconn->networks, def, 0)))
+ goto cleanup;
+ def = NULL;
+
+ event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid,
+ VIR_NETWORK_EVENT_DEFINED,
+ 0);
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkDefFree(def);
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static int testNetworkUndefine(virNetworkPtr network)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virNetworkObjIsActive(privnet)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("Network '%s' is still running"), network->name);
+ goto cleanup;
+ }
+
+ event = virNetworkEventLifecycleNew(network->name, network->uuid,
+ VIR_NETWORK_EVENT_UNDEFINED,
+ 0);
+
+ virNetworkRemoveInactive(privconn->networks, privnet);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static int
+testNetworkUpdate(virNetworkPtr net,
+ unsigned int command,
+ unsigned int section,
+ int parentIndex,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = net->conn->privateData;
+ virNetworkObjPtr network = NULL;
+ int isActive, ret = -1;
+
+ virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
+ VIR_NETWORK_UPDATE_AFFECT_CONFIG,
+ -1);
+
+ network = virNetworkObjFindByUUID(privconn->networks, net->uuid);
+ if (!network) {
+ virReportError(VIR_ERR_NO_NETWORK,
+ "%s", _("no network with matching uuid"));
+ goto cleanup;
+ }
+
+ /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
+ * is active, else change CONFIG
+ */
+ isActive = virNetworkObjIsActive(network);
+ if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE
+ | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
+ VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
+ if (isActive)
+ flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
+ else
+ flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
+ }
+
+ /* update the network config in memory/on disk */
+ if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virNetworkObjEndAPI(&network);
+ return ret;
+}
+
+static int testNetworkCreate(virNetworkPtr network)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virNetworkObjIsActive(privnet)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("Network '%s' is already running"), network->name);
+ goto cleanup;
+ }
+
+ privnet->active = 1;
+ event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
+ VIR_NETWORK_EVENT_STARTED,
+ 0);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static int testNetworkDestroy(virNetworkPtr network)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privnet->active = 0;
+ event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid,
+ VIR_NETWORK_EVENT_STOPPED,
+ 0);
+ if (!privnet->persistent)
+ virNetworkRemoveInactive(privconn->networks, privnet);
+
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static char *testNetworkGetXMLDesc(virNetworkPtr network,
+ unsigned int flags)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virNetworkDefFormat(privnet->def, flags);
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static char *testNetworkGetBridgeName(virNetworkPtr network) {
+ testDriverPtr privconn = network->conn->privateData;
+ char *bridge = NULL;
+ virNetworkObjPtr privnet;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!(privnet->def->bridge)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("network '%s' does not have a bridge name."),
+ privnet->def->name);
+ goto cleanup;
+ }
+
+ ignore_value(VIR_STRDUP(bridge, privnet->def->bridge));
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return bridge;
+}
+
+static int testNetworkGetAutostart(virNetworkPtr network,
+ int *autostart)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ *autostart = privnet->autostart;
+ ret = 0;
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static int testNetworkSetAutostart(virNetworkPtr network,
+ int autostart)
+{
+ testDriverPtr privconn = network->conn->privateData;
+ virNetworkObjPtr privnet;
+ int ret = -1;
+
+ privnet = virNetworkObjFindByName(privconn->networks, network->name);
+ if (privnet == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privnet->autostart = autostart ? 1 : 0;
+ ret = 0;
+
+ cleanup:
+ virNetworkObjEndAPI(&privnet);
+ return ret;
+}
+
+static virNetworkPtr testNetworkLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkObjPtr net;
+ virNetworkPtr ret = NULL;
+
+ net = virNetworkObjFindByUUID(privconn->networks, uuid);
+ if (net == NULL) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static virNetworkPtr testNetworkLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virNetworkObjPtr net;
+ virNetworkPtr ret = NULL;
+
+ net = virNetworkObjFindByName(privconn->networks, name);
+ if (net == NULL) {
+ virReportError(VIR_ERR_NO_NETWORK, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetNetwork(conn, net->def->name, net->def->uuid);
+
+ cleanup:
+ virNetworkObjEndAPI(&net);
+ return ret;
+}
+
+static int
+testConnectNetworkEventRegisterAny(virConnectPtr conn,
+ virNetworkPtr net,
+ int eventID,
+ virConnectNetworkEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virNetworkEventStateRegisterID(conn, driver->eventState,
+ net, eventID, callback,
+ opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectNetworkEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+virNetworkDriver testNetworkDriver = {
+ .connectNumOfNetworks = testConnectNumOfNetworks, /* 0.3.2 */
+ .connectListNetworks = testConnectListNetworks, /* 0.3.2 */
+ .connectNumOfDefinedNetworks = testConnectNumOfDefinedNetworks, /* 0.3.2 */
+ .connectListDefinedNetworks = testConnectListDefinedNetworks, /* 0.3.2 */
+ .connectListAllNetworks = testConnectListAllNetworks, /* 0.10.2 */
+ .connectNetworkEventRegisterAny = testConnectNetworkEventRegisterAny, /* 1.2.1 */
+ .connectNetworkEventDeregisterAny = testConnectNetworkEventDeregisterAny, /* 1.2.1 */
+ .networkLookupByUUID = testNetworkLookupByUUID, /* 0.3.2 */
+ .networkLookupByName = testNetworkLookupByName, /* 0.3.2 */
+ .networkCreateXML = testNetworkCreateXML, /* 0.3.2 */
+ .networkDefineXML = testNetworkDefineXML, /* 0.3.2 */
+ .networkUndefine = testNetworkUndefine, /* 0.3.2 */
+ .networkUpdate = testNetworkUpdate, /* 0.10.2 */
+ .networkCreate = testNetworkCreate, /* 0.3.2 */
+ .networkDestroy = testNetworkDestroy, /* 0.3.2 */
+ .networkGetXMLDesc = testNetworkGetXMLDesc, /* 0.3.2 */
+ .networkGetBridgeName = testNetworkGetBridgeName, /* 0.3.2 */
+ .networkGetAutostart = testNetworkGetAutostart, /* 0.3.2 */
+ .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
+ .networkIsActive = testNetworkIsActive, /* 0.7.3 */
+ .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
+};
diff --git a/src/test/test_network_driver.h b/src/test/test_network_driver.h
new file mode 100644
index 0000000..a87b7a4
--- /dev/null
+++ b/src/test/test_network_driver.h
@@ -0,0 +1 @@
+extern virNetworkDriver testNetworkDriver;
diff --git a/src/test/test_private_driver.h b/src/test/test_private_driver.h
new file mode 100644
index 0000000..751933c
--- /dev/null
+++ b/src/test/test_private_driver.h
@@ -0,0 +1,70 @@
+#ifndef __TEST_DRIVER_H__
+# define __TEST_DRIVER_H__
+
+# define MAX_CPUS 128
+
+struct _testCell {
+ unsigned long mem;
+ unsigned long freeMem;
+ int numCpus;
+ virCapsHostNUMACellCPU cpus[MAX_CPUS];
+};
+typedef struct _testCell testCell;
+typedef struct _testCell *testCellPtr;
+
+# define MAX_CELLS 128
+
+struct _testAuth {
+ char *username;
+ char *password;
+};
+typedef struct _testAuth testAuth;
+typedef struct _testAuth *testAuthPtr;
+
+struct _testDriver {
+ virMutex lock;
+
+ virNodeInfo nodeInfo;
+ virInterfaceObjList ifaces;
+ bool transaction_running;
+ virInterfaceObjList backupIfaces;
+ virStoragePoolObjList pools;
+ virNodeDeviceObjList devs;
+ int numCells;
+ testCell cells[MAX_CELLS];
+ size_t numAuths;
+ testAuthPtr auths;
+
+ /* virAtomic access only */
+ volatile int nextDomID;
+
+ /* immutable pointer, immutable object after being initialized with
+ * testBuildCapabilities */
+ virCapsPtr caps;
+
+ /* immutable pointer, immutable object */
+ virDomainXMLOptionPtr xmlopt;
+
+ /* immutable pointer, self-locking APIs */
+ virDomainObjListPtr domains;
+ virNetworkObjListPtr networks;
+ virObjectEventStatePtr eventState;
+};
+typedef struct _testDriver testDriver;
+typedef testDriver *testDriverPtr;
+
+# define VIR_FROM_THIS VIR_FROM_TEST
+
+extern unsigned long long defaultPoolAlloc;
+
+extern unsigned long long defaultPoolCap;
+
+void testDriverLock(testDriverPtr driver);
+void testDriverUnlock(testDriverPtr driver);
+
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool);
+
+void testObjectEventQueue(testDriverPtr driver,
+ virObjectEventPtr event);
+
+#endif /* __TEST_DRIVER_H__ */
diff --git a/src/test/test_storage_driver.c b/src/test/test_storage_driver.c
new file mode 100644
index 0000000..bda43c1
--- /dev/null
+++ b/src/test/test_storage_driver.c
@@ -0,0 +1,1517 @@
+/*
+ * test_storage_driver.c: A "mock" hypervisor for use by application unit tests
+ *
+ * Copyright (C) 2006-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Daniel Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xpathInternals.h>
+
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "test_driver.h"
+#include "virbuffer.h"
+#include "viruuid.h"
+#include "capabilities.h"
+#include "configmake.h"
+#include "viralloc.h"
+#include "network_conf.h"
+#include "interface_conf.h"
+#include "domain_conf.h"
+#include "domain_event.h"
+#include "network_event.h"
+#include "snapshot_conf.h"
+#include "fdstream.h"
+#include "storage_conf.h"
+#include "storage_event.h"
+#include "node_device_conf.h"
+#include "node_device_event.h"
+#include "virxml.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virrandom.h"
+#include "virstring.h"
+#include "cpu/cpu.h"
+#include "virauth.h"
+#include "viratomic.h"
+#include "virdomainobjlist.h"
+#include "virhostcpu.h"
+
+#include "test_storage_driver.h"
+
+#include "test_private_driver.h"
+
+static int
+testConnectNumOfStoragePools(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numActive = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++)
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
+ numActive++;
+ testDriverUnlock(privconn);
+
+ return numActive;
+}
+
+static int
+testConnectListStoragePools(virConnectPtr conn,
+ char **const names,
+ int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+ VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ goto error;
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static int
+testConnectNumOfDefinedStoragePools(virConnectPtr conn)
+{
+ testDriverPtr privconn = conn->privateData;
+ int numInactive = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
+ numInactive++;
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return numInactive;
+}
+
+static int
+testConnectListDefinedStoragePools(virConnectPtr conn,
+ char **const names,
+ int nnames)
+{
+ testDriverPtr privconn = conn->privateData;
+ int n = 0;
+ size_t i;
+
+ testDriverLock(privconn);
+ memset(names, 0, sizeof(*names)*nnames);
+ for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+ VIR_STRDUP(names[n++], privconn->pools.objs[i]->def->name) < 0) {
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ goto error;
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ return n;
+
+ error:
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ testDriverUnlock(privconn);
+ return -1;
+}
+
+static int
+testConnectListAllStoragePools(virConnectPtr conn,
+ virStoragePoolPtr **pools,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL, -1);
+
+ testDriverLock(privconn);
+ ret = virStoragePoolObjListExport(conn, privconn->pools, pools,
+ NULL, flags);
+ testDriverUnlock(privconn);
+
+ return ret;
+}
+
+static const char *defaultPoolSourcesLogicalXML =
+"<sources>\n"
+" <source>\n"
+" <device path='/dev/sda20'/>\n"
+" <name>testvg1</name>\n"
+" <format type='lvm2'/>\n"
+" </source>\n"
+" <source>\n"
+" <device path='/dev/sda21'/>\n"
+" <name>testvg2</name>\n"
+" <format type='lvm2'/>\n"
+" </source>\n"
+"</sources>\n";
+
+static const char *defaultPoolSourcesNetFSXML =
+"<sources>\n"
+" <source>\n"
+" <host name='%s'/>\n"
+" <dir path='/testshare'/>\n"
+" <format type='nfs'/>\n"
+" </source>\n"
+"</sources>\n";
+
+static char *
+testConnectFindStoragePoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *type,
+ const char *srcSpec,
+ unsigned int flags)
+{
+ virStoragePoolSourcePtr source = NULL;
+ int pool_type;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pool_type = virStoragePoolTypeFromString(type);
+ if (!pool_type) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown storage pool type %s"), type);
+ goto cleanup;
+ }
+
+ if (srcSpec) {
+ source = virStoragePoolDefParseSourceString(srcSpec, pool_type);
+ if (!source)
+ goto cleanup;
+ }
+
+ switch (pool_type) {
+
+ case VIR_STORAGE_POOL_LOGICAL:
+ ignore_value(VIR_STRDUP(ret, defaultPoolSourcesLogicalXML));
+ break;
+
+ case VIR_STORAGE_POOL_NETFS:
+ if (!source || !source->hosts[0].name) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("hostname must be specified for netfs sources"));
+ goto cleanup;
+ }
+
+ ignore_value(virAsprintf(&ret, defaultPoolSourcesNetFSXML,
+ source->hosts[0].name));
+ break;
+
+ default:
+ virReportError(VIR_ERR_NO_SUPPORT,
+ _("pool type '%s' does not support source discovery"), type);
+ }
+
+ cleanup:
+ virStoragePoolSourceFree(source);
+ return ret;
+}
+
+static int
+testConnectStoragePoolEventRegisterAny(virConnectPtr conn,
+ virStoragePoolPtr pool,
+ int eventID,
+ virConnectStoragePoolEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret;
+
+ if (virStoragePoolEventStateRegisterID(conn, driver->eventState,
+ pool, eventID, callback,
+ opaque, freecb, &ret) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+testConnectStoragePoolEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ testDriverPtr driver = conn->privateData;
+ int ret = 0;
+
+ if (virObjectEventStateDeregisterID(conn, driver->eventState,
+ callbackID) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByName(virConnectPtr conn,
+ const char *name)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ pool = virStoragePoolObjFindByName(&privconn->pools, name);
+ testDriverUnlock(privconn);
+
+ if (pool == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByVolume(virStorageVolPtr vol)
+{
+ return testStoragePoolLookupByName(vol->conn, vol->pool);
+}
+
+static virStoragePoolPtr
+testStoragePoolLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
+ testDriverUnlock(privconn);
+
+ if (pool == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolCreateXML(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool = NULL;
+ virStoragePoolPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ if (!(def = virStoragePoolDefParseString(xml)))
+ goto cleanup;
+
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, def->uuid);
+ if (!pool)
+ pool = virStoragePoolObjFindByName(&privconn->pools, def->name);
+ if (pool) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("storage pool already exists"));
+ goto cleanup;
+ }
+
+ if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+ goto cleanup;
+ def = NULL;
+
+ if (testStoragePoolObjSetDefaults(pool) == -1) {
+ virStoragePoolObjRemove(&privconn->pools, pool);
+ pool = NULL;
+ goto cleanup;
+ }
+ pool->active = 1;
+
+ event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
+ VIR_STORAGE_POOL_EVENT_STARTED,
+ 0);
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ virStoragePoolDefFree(def);
+ testObjectEventQueue(privconn, event);
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static virStoragePoolPtr
+testStoragePoolDefineXML(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags)
+{
+ testDriverPtr privconn = conn->privateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool = NULL;
+ virStoragePoolPtr ret = NULL;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ if (!(def = virStoragePoolDefParseString(xml)))
+ goto cleanup;
+
+ def->capacity = defaultPoolCap;
+ def->allocation = defaultPoolAlloc;
+ def->available = defaultPoolCap - defaultPoolAlloc;
+
+ if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+ goto cleanup;
+ def = NULL;
+
+ event = virStoragePoolEventLifecycleNew(pool->def->name, pool->def->uuid,
+ VIR_STORAGE_POOL_EVENT_DEFINED,
+ 0);
+
+ if (testStoragePoolObjSetDefaults(pool) == -1) {
+ virStoragePoolObjRemove(&privconn->pools, pool);
+ pool = NULL;
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid,
+ NULL, NULL);
+
+ cleanup:
+ virStoragePoolDefFree(def);
+ testObjectEventQueue(privconn, event);
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+testStoragePoolUndefine(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+
+ event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
+ VIR_STORAGE_POOL_EVENT_UNDEFINED,
+ 0);
+
+ virStoragePoolObjRemove(&privconn->pools, privpool);
+ privpool = NULL;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ testObjectEventQueue(privconn, event);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+testStoragePoolBuild(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolDestroy(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privpool->active = 0;
+ event = virStoragePoolEventLifecycleNew(privpool->def->name, privpool->def->uuid,
+ VIR_STORAGE_POOL_EVENT_STOPPED,
+ 0);
+
+ if (privpool->configFile == NULL) {
+ virStoragePoolObjRemove(&privconn->pools, privpool);
+ privpool = NULL;
+ }
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ testDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+testStoragePoolDelete(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolRefresh(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ event = virStoragePoolEventRefreshNew(pool->name, pool->uuid);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolGetInfo(virStoragePoolPtr pool,
+ virStoragePoolInfoPtr info)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ memset(info, 0, sizeof(virStoragePoolInfo));
+ if (privpool->active)
+ info->state = VIR_STORAGE_POOL_RUNNING;
+ else
+ info->state = VIR_STORAGE_POOL_INACTIVE;
+ info->capacity = privpool->def->capacity;
+ info->allocation = privpool->def->allocation;
+ info->available = privpool->def->available;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+testStoragePoolGetXMLDesc(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virStoragePoolDefFormat(privpool->def);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolGetAutostart(virStoragePoolPtr pool,
+ int *autostart)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!privpool->configFile) {
+ *autostart = 0;
+ } else {
+ *autostart = privpool->autostart;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolSetAutostart(virStoragePoolPtr pool,
+ int autostart)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!privpool->configFile) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ "%s", _("pool has no config file"));
+ goto cleanup;
+ }
+
+ autostart = (autostart != 0);
+ privpool->autostart = autostart;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolNumOfVolumes(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ ret = privpool->volumes.count;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStoragePoolListVolumes(virStoragePoolPtr pool,
+ char **const names,
+ int maxnames)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ size_t i = 0;
+ int n = 0;
+
+ memset(names, 0, maxnames * sizeof(*names));
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
+ if (VIR_STRDUP(names[n++], privpool->volumes.objs[i]->name) < 0)
+ goto cleanup;
+ }
+
+ virStoragePoolObjUnlock(privpool);
+ return n;
+
+ cleanup:
+ for (n = 0; n < maxnames; n++)
+ VIR_FREE(names[i]);
+
+ memset(names, 0, maxnames * sizeof(*names));
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return -1;
+}
+
+static int
+testStoragePoolListAllVolumes(virStoragePoolPtr obj,
+ virStorageVolPtr **vols,
+ unsigned int flags)
+{
+ testDriverPtr privconn = obj->conn->privateData;
+ virStoragePoolObjPtr pool;
+ size_t i;
+ virStorageVolPtr *tmp_vols = NULL;
+ virStorageVolPtr vol = NULL;
+ int nvols = 0;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, obj->uuid);
+ testDriverUnlock(privconn);
+
+ if (!pool) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, "%s",
+ _("no storage pool with matching uuid"));
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("storage pool is not active"));
+ goto cleanup;
+ }
+
+ /* Just returns the volumes count */
+ if (!vols) {
+ ret = pool->volumes.count;
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(tmp_vols, pool->volumes.count + 1) < 0)
+ goto cleanup;
+
+ for (i = 0; i < pool->volumes.count; i++) {
+ if (!(vol = virGetStorageVol(obj->conn, pool->def->name,
+ pool->volumes.objs[i]->name,
+ pool->volumes.objs[i]->key,
+ NULL, NULL)))
+ goto cleanup;
+ tmp_vols[nvols++] = vol;
+ }
+
+ *vols = tmp_vols;
+ tmp_vols = NULL;
+ ret = nvols;
+
+ cleanup:
+ if (tmp_vols) {
+ for (i = 0; i < nvols; i++)
+ virObjectUnref(tmp_vols[i]);
+ VIR_FREE(tmp_vols);
+ }
+
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByName(virStoragePoolPtr pool,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ virStorageVolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, name);
+
+ if (!privvol) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"), name);
+ goto cleanup;
+ }
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key,
+ NULL, NULL);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByKey(virConnectPtr conn,
+ const char *key)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ virStorageVolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+ virStorageVolDefPtr privvol =
+ virStorageVolDefFindByKey(privconn->pools.objs[i], key);
+
+ if (privvol) {
+ ret = virGetStorageVol(conn,
+ privconn->pools.objs[i]->def->name,
+ privvol->name,
+ privvol->key,
+ NULL, NULL);
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ break;
+ }
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ if (!ret)
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching key '%s'"), key);
+
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolLookupByPath(virConnectPtr conn,
+ const char *path)
+{
+ testDriverPtr privconn = conn->privateData;
+ size_t i;
+ virStorageVolPtr ret = NULL;
+
+ testDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+ virStorageVolDefPtr privvol =
+ virStorageVolDefFindByPath(privconn->pools.objs[i], path);
+
+ if (privvol) {
+ ret = virGetStorageVol(conn,
+ privconn->pools.objs[i]->def->name,
+ privvol->name,
+ privvol->key,
+ NULL, NULL);
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ break;
+ }
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ testDriverUnlock(privconn);
+
+ if (!ret)
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching path '%s'"), path);
+
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolCreateXML(virStoragePoolPtr pool,
+ const char *xmldesc,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol = NULL;
+ virStorageVolPtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
+ if (privvol == NULL)
+ goto cleanup;
+
+ if (virStorageVolDefFindByName(privpool, privvol->name)) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("storage vol already exists"));
+ goto cleanup;
+ }
+
+ /* Make sure enough space */
+ if ((privpool->def->allocation + privvol->target.allocation) >
+ privpool->def->capacity) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Not enough free space in pool for volume '%s'"),
+ privvol->name);
+ goto cleanup;
+ }
+
+ if (virAsprintf(&privvol->target.path, "%s/%s",
+ privpool->def->target.path,
+ privvol->name) == -1)
+ goto cleanup;
+
+ if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
+ VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
+ privpool->volumes.count, privvol) < 0)
+ goto cleanup;
+
+ privpool->def->allocation += privvol->target.allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key,
+ NULL, NULL);
+ privvol = NULL;
+
+ cleanup:
+ virStorageVolDefFree(privvol);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static virStorageVolPtr
+testStorageVolCreateXMLFrom(virStoragePoolPtr pool,
+ const char *xmldesc,
+ virStorageVolPtr clonevol,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol = NULL, origvol = NULL;
+ virStorageVolPtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefParseString(privpool->def, xmldesc, 0);
+ if (privvol == NULL)
+ goto cleanup;
+
+ if (virStorageVolDefFindByName(privpool, privvol->name)) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("storage vol already exists"));
+ goto cleanup;
+ }
+
+ origvol = virStorageVolDefFindByName(privpool, clonevol->name);
+ if (!origvol) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ clonevol->name);
+ goto cleanup;
+ }
+
+ /* Make sure enough space */
+ if ((privpool->def->allocation + privvol->target.allocation) >
+ privpool->def->capacity) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Not enough free space in pool for volume '%s'"),
+ privvol->name);
+ goto cleanup;
+ }
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ if (virAsprintf(&privvol->target.path, "%s/%s",
+ privpool->def->target.path,
+ privvol->name) == -1)
+ goto cleanup;
+
+ if (VIR_STRDUP(privvol->key, privvol->target.path) < 0 ||
+ VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
+ privpool->volumes.count, privvol) < 0)
+ goto cleanup;
+
+ privpool->def->allocation += privvol->target.allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key,
+ NULL, NULL);
+ privvol = NULL;
+
+ cleanup:
+ virStorageVolDefFree(privvol);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+testStorageVolDelete(virStorageVolPtr vol,
+ unsigned int flags)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ size_t i;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+
+ privpool->def->allocation -= privvol->target.allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ for (i = 0; i < privpool->volumes.count; i++) {
+ if (privpool->volumes.objs[i] == privvol) {
+ virStorageVolDefFree(privvol);
+
+ VIR_DELETE_ELEMENT(privpool->volumes.objs, i, privpool->volumes.count);
+ break;
+ }
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int testStorageVolumeTypeForPool(int pooltype)
+{
+
+ switch (pooltype) {
+ case VIR_STORAGE_POOL_DIR:
+ case VIR_STORAGE_POOL_FS:
+ case VIR_STORAGE_POOL_NETFS:
+ return VIR_STORAGE_VOL_FILE;
+ default:
+ return VIR_STORAGE_VOL_BLOCK;
+ }
+}
+
+static int
+testStorageVolGetInfo(virStorageVolPtr vol,
+ virStorageVolInfoPtr info)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ memset(info, 0, sizeof(*info));
+ info->type = testStorageVolumeTypeForPool(privpool->def->type);
+ info->capacity = privvol->target.capacity;
+ info->allocation = privvol->target.allocation;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+testStorageVolGetXMLDesc(virStorageVolPtr vol,
+ unsigned int flags)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ ret = virStorageVolDefFormat(privpool->def, privvol);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+testStorageVolGetPath(virStorageVolPtr vol)
+{
+ testDriverPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ char *ret = NULL;
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ vol->pool);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ virReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ ignore_value(VIR_STRDUP(ret, privvol->target.path));
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+int testStoragePoolObjSetDefaults(virStoragePoolObjPtr pool)
+{
+
+ pool->def->capacity = defaultPoolCap;
+ pool->def->allocation = defaultPoolAlloc;
+ pool->def->available = defaultPoolCap - defaultPoolAlloc;
+
+ return VIR_STRDUP(pool->configFile, "");
+}
+
+static int testStoragePoolIsActive(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr obj;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+ testDriverUnlock(privconn);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+ ret = virStoragePoolObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virStoragePoolObjUnlock(obj);
+ return ret;
+}
+
+static int testStoragePoolIsPersistent(virStoragePoolPtr pool)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr obj;
+ int ret = -1;
+
+ testDriverLock(privconn);
+ obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+ testDriverUnlock(privconn);
+ if (!obj) {
+ virReportError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+ ret = obj->configFile ? 1 : 0;
+
+ cleanup:
+ if (obj)
+ virStoragePoolObjUnlock(obj);
+ return ret;
+}
+
+static int
+testStoragePoolCreate(virStoragePoolPtr pool,
+ unsigned int flags)
+{
+ testDriverPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+ virObjectEventPtr event = NULL;
+
+ virCheckFlags(0, -1);
+
+ testDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools,
+ pool->name);
+ testDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"), pool->name);
+ goto cleanup;
+ }
+
+ privpool->active = 1;
+
+ event = virStoragePoolEventLifecycleNew(pool->name, pool->uuid,
+ VIR_STORAGE_POOL_EVENT_STARTED,
+ 0);
+ ret = 0;
+
+ cleanup:
+ testObjectEventQueue(privconn, event);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+virStorageDriver testStorageDriver = {
+ .connectNumOfStoragePools = testConnectNumOfStoragePools, /* 0.5.0 */
+ .connectListStoragePools = testConnectListStoragePools, /* 0.5.0 */
+ .connectNumOfDefinedStoragePools = testConnectNumOfDefinedStoragePools, /* 0.5.0 */
+ .connectListDefinedStoragePools = testConnectListDefinedStoragePools, /* 0.5.0 */
+ .connectListAllStoragePools = testConnectListAllStoragePools, /* 0.10.2 */
+ .connectFindStoragePoolSources = testConnectFindStoragePoolSources, /* 0.5.0 */
+ .connectStoragePoolEventRegisterAny = testConnectStoragePoolEventRegisterAny, /* 2.0.0 */
+ .connectStoragePoolEventDeregisterAny = testConnectStoragePoolEventDeregisterAny, /* 2.0.0 */
+ .storagePoolLookupByName = testStoragePoolLookupByName, /* 0.5.0 */
+ .storagePoolLookupByUUID = testStoragePoolLookupByUUID, /* 0.5.0 */
+ .storagePoolLookupByVolume = testStoragePoolLookupByVolume, /* 0.5.0 */
+ .storagePoolCreateXML = testStoragePoolCreateXML, /* 0.5.0 */
+ .storagePoolDefineXML = testStoragePoolDefineXML, /* 0.5.0 */
+ .storagePoolBuild = testStoragePoolBuild, /* 0.5.0 */
+ .storagePoolUndefine = testStoragePoolUndefine, /* 0.5.0 */
+ .storagePoolCreate = testStoragePoolCreate, /* 0.5.0 */
+ .storagePoolDestroy = testStoragePoolDestroy, /* 0.5.0 */
+ .storagePoolDelete = testStoragePoolDelete, /* 0.5.0 */
+ .storagePoolRefresh = testStoragePoolRefresh, /* 0.5.0 */
+ .storagePoolGetInfo = testStoragePoolGetInfo, /* 0.5.0 */
+ .storagePoolGetXMLDesc = testStoragePoolGetXMLDesc, /* 0.5.0 */
+ .storagePoolGetAutostart = testStoragePoolGetAutostart, /* 0.5.0 */
+ .storagePoolSetAutostart = testStoragePoolSetAutostart, /* 0.5.0 */
+ .storagePoolNumOfVolumes = testStoragePoolNumOfVolumes, /* 0.5.0 */
+ .storagePoolListVolumes = testStoragePoolListVolumes, /* 0.5.0 */
+ .storagePoolListAllVolumes = testStoragePoolListAllVolumes, /* 0.10.2 */
+
+ .storageVolLookupByName = testStorageVolLookupByName, /* 0.5.0 */
+ .storageVolLookupByKey = testStorageVolLookupByKey, /* 0.5.0 */
+ .storageVolLookupByPath = testStorageVolLookupByPath, /* 0.5.0 */
+ .storageVolCreateXML = testStorageVolCreateXML, /* 0.5.0 */
+ .storageVolCreateXMLFrom = testStorageVolCreateXMLFrom, /* 0.6.4 */
+ .storageVolDelete = testStorageVolDelete, /* 0.5.0 */
+ .storageVolGetInfo = testStorageVolGetInfo, /* 0.5.0 */
+ .storageVolGetXMLDesc = testStorageVolGetXMLDesc, /* 0.5.0 */
+ .storageVolGetPath = testStorageVolGetPath, /* 0.5.0 */
+ .storagePoolIsActive = testStoragePoolIsActive, /* 0.7.3 */
+ .storagePoolIsPersistent = testStoragePoolIsPersistent, /* 0.7.3 */
+};
diff --git a/src/test/test_storage_driver.h b/src/test/test_storage_driver.h
new file mode 100644
index 0000000..fd29eda
--- /dev/null
+++ b/src/test/test_storage_driver.h
@@ -0,0 +1 @@
+extern virStorageDriver testStorageDriver;
--
2.9.3
4
3
The effect of 2/3 will be more apparent after apibuild.py speedups
(to be written).
Ján Tomko (3):
docs/Makefile.am: remove redundant variables
docs/Makefile.am: build hvsupport.html earlier
docs: drop todo.html
.gitignore | 1 -
docs/Makefile.am | 44 +++---------------
docs/sitemap.html.in | 4 --
docs/todo.cfg-example | 26 -----------
docs/todo.pl | 125 --------------------------------------------------
5 files changed, 7 insertions(+), 193 deletions(-)
delete mode 100644 docs/todo.cfg-example
delete mode 100755 docs/todo.pl
--
2.7.3
3
7
[libvirt] [PATCH] qemu: map "virtio" video model to "virt" machtype correctly (arm/aarch64)
by Laszlo Ersek 16 Sep '16
by Laszlo Ersek 16 Sep '16
16 Sep '16
Most of QEMU's PCI display device models, such as:
libvirt video/model/@type QEMU -device
------------------------- ------------
cirrus cirrus-vga
vga VGA
qxl qxl-vga
virtio virtio-vga
come with a linear framebuffer (sometimes called "VGA compatibility
framebuffer"). This linear framebuffer lives in one of the PCI device's
MMIO BARs, and allows guest code (primarily: firmware drivers, and
non-accelerated OS drivers) to display graphics with direct memory access.
Due to architectural reasons on aarch64/KVM hosts, this kind of
framebuffer doesn't / can't work in
qemu-system-(arm|aarch64) -M virt
machines. Cache coherency issues guarantee a corrupted / unusable display.
The problem has been researched by several people, including kvm-arm
maintainers, and it's been decided that the best way (practically the only
way) to have boot time graphics for such guests is to consolidate on
QEMU's "virtio-gpu-pci" device.
>From <https://bugzilla.redhat.com/show_bug.cgi?id=1195176>, libvirt
supports
<devices>
<video>
<model type='virtio'/>
</video>
</devices>
but libvirt unconditionally maps @type='virtio' to QEMU's "virtio-vga"
device model. (See the qemuBuildDeviceVideoStr() function and the
"qemuDeviceVideo" enum impl.)
According to the above, this is not right for the "virt" machine type; the
qemu-system-(arm|aarch64) binaries don't even recognize the "virtio-vga"
device model (justifiedly). Whereas "virtio-gpu-pci", which is a pure
virtio device without a compatibility framebuffer, is available, and works
fine.
(The ArmVirtQemu ("AAVMF") platform of edk2 -- that is, the UEFI firmware
for "virt" -- supports "virtio-gpu-pci", as of upstream commit
3ef3209d3028. See
<https://tianocore.acgmultimedia.com/show_bug.cgi?id=66>.)
Override the default mapping of "virtio", from "virtio-vga" to
"virtio-gpu-pci", if qemuDomainMachineIsVirt() evaluates to true.
Cc: Andrea Bolognani <abologna(a)redhat.com>
Cc: Drew Jones <drjones(a)redhat.com>
Cc: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Suggested-by: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1372901
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
---
src/qemu/qemu_command.c | 4 ++
tests/qemuxml2argvtest.c | 5 +++
tests/qemuxml2xmltest.c | 5 +++
tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args | 26 +++++++++++
tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml | 36 ++++++++++++++++
tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml | 45 ++++++++++++++++++++
6 files changed, 121 insertions(+)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863b9abb..038c38f2217c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4325,6 +4325,10 @@ qemuBuildDeviceVideoStr(const virDomainDef *def,
virDomainVideoTypeToString(video->type));
goto error;
}
+ if (video->type == VIR_DOMAIN_VIDEO_TYPE_VIRTIO &&
+ qemuDomainMachineIsVirt(def)) {
+ model = "virtio-gpu-pci";
+ }
} else {
if (video->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index dbb0e4d56142..e8540779a4b5 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1872,6 +1872,11 @@ mymain(void)
QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM,
QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI);
+ DO_TEST("aarch64-video-virtio-gpu-pci",
+ QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+ QEMU_CAPS_DEVICE_VIRTIO_GPU, QEMU_CAPS_BOOTINDEX);
DO_TEST("aarch64-aavmf-virtio-mmio",
QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DTB,
QEMU_CAPS_DEVICE_VIRTIO_MMIO,
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 14c2b0ccf2ce..fb05c8571411 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -831,6 +831,11 @@ mymain(void)
QEMU_CAPS_DEVICE_VIRTIO_RNG, QEMU_CAPS_OBJECT_RNG_RANDOM,
QEMU_CAPS_OBJECT_GPEX, QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI);
+ DO_TEST("aarch64-video-virtio-gpu-pci",
+ QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_GPEX,
+ QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+ QEMU_CAPS_DEVICE_VIRTIO_GPU, QEMU_CAPS_BOOTINDEX);
DO_TEST_FULL("aarch64-gic-none", WHEN_BOTH, GIC_NONE, NONE);
DO_TEST_FULL("aarch64-gic-none-v2", WHEN_BOTH, GIC_V2, NONE);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args
new file mode 100644
index 000000000000..56dbdfb66fa2
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.args
@@ -0,0 +1,26 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/opt/qemu-installed/bin/qemu-system-aarch64 \
+-name aarch64-vgpu \
+-S \
+-M virt \
+-cpu cortex-a57 \
+-m 1024 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid f3197c89-6457-44fe-b26d-897090ba6541 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-aarch64-vgpu/monitor.sock,server,nowait \
+-device ioh3420,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device ioh3420,port=0x9,chassis=2,id=pci.2,bus=pcie.0,multifunction=on,\
+addr=0x1.0x1 \
+-device virtio-net-pci,vlan=0,id=net0,mac=52:54:00:73:34:53,bus=pci.1,\
+addr=0x0,bootindex=1 \
+-net user,vlan=0,name=hostnet0 \
+-device virtio-gpu-pci,id=video0,bus=pci.2,addr=0x0
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml
new file mode 100644
index 000000000000..4b52a731b043
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-aarch64-video-virtio-gpu-pci.xml
@@ -0,0 +1,36 @@
+<domain type='qemu'>
+ <name>aarch64-vgpu</name>
+ <uuid>f3197c89-6457-44fe-b26d-897090ba6541</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <features>
+ <acpi/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>cortex-a57</model>
+ </cpu>
+ <devices>
+ <emulator>/opt/qemu-installed/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/>
+ </controller>
+ <interface type='user'>
+ <mac address='52:54:00:73:34:53'/>
+ <model type='virtio'/>
+ <boot order='1'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <video>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml
new file mode 100644
index 000000000000..26f6a51622ef
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-aarch64-video-virtio-gpu-pci.xml
@@ -0,0 +1,45 @@
+<domain type='qemu'>
+ <name>aarch64-vgpu</name>
+ <uuid>f3197c89-6457-44fe-b26d-897090ba6541</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <features>
+ <acpi/>
+ <gic version='2'/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>cortex-a57</model>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/opt/qemu-installed/bin/qemu-system-aarch64</emulator>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='ioh3420'/>
+ <target chassis='1' port='0x8'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='ioh3420'/>
+ <target chassis='2' port='0x9'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1' multifunction='on'/>
+ </controller>
+ <interface type='user'>
+ <mac address='52:54:00:73:34:53'/>
+ <model type='virtio'/>
+ <boot order='1'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <video>
+ <model type='virtio' heads='1' primary='yes'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </video>
+ </devices>
+</domain>
--
2.9.2
2
3
16 Sep '16
There is nothing Linux-specific in that function. Also since commit
8c3b5bf48123783b812b97360db7ac51f1889e17 mingw build is broken due to
the fact that this function is not compiled in the library.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
Pushed as trivial build-breaker fix.
src/util/virhostcpu.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index 856d83c3e49b..f68176f387ec 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -781,21 +781,6 @@ virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
return ret;
}
-int
-virHostCPUStatsAssign(virNodeCPUStatsPtr param,
- const char *name,
- unsigned long long value)
-{
- if (virStrcpyStatic(param->field, name) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("kernel cpu time field is too long"
- " for the destination"));
- return -1;
- }
- param->value = value;
- return 0;
-}
-
# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))
int
@@ -953,6 +938,22 @@ virHostCPUParseMapLinux(int max_cpuid, const char *path)
int
+virHostCPUStatsAssign(virNodeCPUStatsPtr param,
+ const char *name,
+ unsigned long long value)
+{
+ if (virStrcpyStatic(param->field, name) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("kernel cpu time field is too long"
+ " for the destination"));
+ return -1;
+ }
+ param->value = value;
+ return 0;
+}
+
+
+int
virHostCPUGetInfo(virArch hostarch ATTRIBUTE_UNUSED,
unsigned int *cpus ATTRIBUTE_UNUSED,
unsigned int *mhz ATTRIBUTE_UNUSED,
--
2.10.0
1
0
[libvirt] [PATCH v1 1/1] qemu/gluster: add option for tuning debug logging level
by Prasanna Kumar Kalever 16 Sep '16
by Prasanna Kumar Kalever 16 Sep '16
16 Sep '16
This helps in selecting log level of the gluster gfapi, output to stderr.
The option is 'qemu_gfapi_debuglevel', can be tuned by editing
'/etc/libvirt/qemu.conf'
Debug levels ranges 0-9, with 9 being the most verbose, and 0 representing
no debugging output. The default is the same as it was before, which
is a level of 4. The current logging levels defined in the gluster
gfapi are:
0 - None
1 - Emergency
2 - Alert
3 - Critical
4 - Error
5 - Warning
6 - Notice
7 - Info
8 - Debug
9 - Trace
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever(a)redhat.com>
--
v1: Initial post
---
src/qemu/qemu.conf | 20 ++++++++++++++++++++
src/qemu/qemu_command.c | 12 +++++++++++-
src/qemu/qemu_conf.c | 3 +++
src/qemu/qemu_conf.h | 1 +
src/util/virstoragefile.h | 2 ++
5 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index e4c2aae..c6c8f3a 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -621,3 +621,23 @@
# rollover when a size limit is hit.
#
#stdio_handler = "logd"
+
+# Qemu gluster libgfapi log level, debug levels are 0-9, with 9 being the
+# most verbose, and 0 representing no debugging output.
+#
+# The current logging levels defined in the gluster GFAPI are:
+#
+# 0 - None
+# 1 - Emergency
+# 2 - Alert
+# 3 - Critical
+# 4 - Error
+# 5 - Warning
+# 6 - Notice
+# 7 - Info
+# 8 - Debug
+# 9 - Trace
+#
+# Defaults to 4
+#
+# qemu_gfapi_debuglevel = 9
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863..650eedc 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -859,6 +859,7 @@ qemuBuildGlusterDriveJSON(virStorageSourcePtr src)
/* { driver:"gluster",
* volume:"testvol",
* path:"/a.img",
+ * debug:9,
* server :[{type:"tcp", host:"1.2.3.4", port:24007},
* {type:"unix", socket:"/tmp/glusterd.socket"}, ...]}
*/
@@ -866,6 +867,7 @@ qemuBuildGlusterDriveJSON(virStorageSourcePtr src)
"s:driver", protocol,
"s:volume", src->volume,
"s:path", src->path,
+ "u:debug", src->debug_level,
"a:server", servers, NULL) < 0)
virJSONValueFree(servers);
@@ -2177,6 +2179,7 @@ qemuBuildDriveDevStr(const virDomainDef *def,
static int
qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
+ virQEMUDriverConfigPtr cfg,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
@@ -2255,6 +2258,13 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
virCommandAddArg(cmd, "-drive");
+ if (disk->src &&
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
+ if(cfg->qemuGfapiDebugLevel) {
+ disk->src->debug_level = cfg->qemuGfapiDebugLevel;
+ }
+ }
+
if (!(optstr = qemuBuildDriveStr(disk, driveBoot, qemuCaps)))
return -1;
virCommandAddArg(cmd, optstr);
@@ -9613,7 +9623,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildHubCommandLine(cmd, def, qemuCaps) < 0)
goto error;
- if (qemuBuildDiskDriveCommandLine(cmd, def, qemuCaps) < 0)
+ if (qemuBuildDiskDriveCommandLine(cmd, cfg, def, qemuCaps) < 0)
goto error;
if (qemuBuildFSDevCommandLine(cmd, def, qemuCaps) < 0)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index dad8334..d245cec 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -311,6 +311,7 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
cfg->seccompSandbox = -1;
cfg->logTimestamp = true;
+ cfg->qemuGfapiDebugLevel = 4;
cfg->stdioLogD = true;
#ifdef DEFAULT_LOADER_NVRAM
@@ -780,6 +781,8 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
goto cleanup;
}
}
+ if (virConfGetValueUInt(conf, "qemu_gfapi_debuglevel", &cfg->qemuGfapiDebugLevel) < 0)
+ goto cleanup;
ret = 0;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index d8232cc..fe70d9b 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -190,6 +190,7 @@ struct _virQEMUDriverConfig {
virFirmwarePtr *firmwares;
size_t nfirmwares;
+ unsigned int qemuGfapiDebugLevel;
};
/* Main driver state */
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 3d09468..9f3add3 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -237,6 +237,8 @@ struct _virStorageSource {
virStorageAuthDefPtr auth;
virStorageEncryptionPtr encryption;
+ unsigned int debug_level;
+
char *driverName;
int format; /* virStorageFileFormat in domain backing chains, but
* pool-specific enum for storage volumes */
--
2.7.4
4
5
[libvirt] [PATCH v2 1/1] [WIP] qemu/gluster: add option for tuning debug logging level
by Prasanna Kumar Kalever 15 Sep '16
by Prasanna Kumar Kalever 15 Sep '16
15 Sep '16
This helps in selecting log level of the gluster gfapi, output to stderr.
The option is 'qemu_gfapi_debuglevel', can be tuned by editing
'/etc/libvirt/qemu.conf'
Debug levels ranges 0-9, with 9 being the most verbose, and 0 representing
no debugging output. The default is the same as it was before, which
is a level of 4. The current logging levels defined in the gluster
gfapi are:
0 - None
1 - Emergency
2 - Alert
3 - Critical
4 - Error
5 - Warning
6 - Notice
7 - Info
8 - Debug
9 - Trace
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever(a)redhat.com>
--
v2:
Modify test cases and syntax check changes as suggested by Peter in v1.
Rename qemu_gfapi_debuglevel to glusterfs_debug_level as per Daniel comments.
Fix to make debug_level changes effects on URI along with JSON.
TODO:
* changes in libvirtd_qemu.aug
Which I don't understand for now
* comment on debug_level variable in storage source
Not sure what is the right place
* Capablities check
v1:
Initial post
---
src/qemu/qemu.conf | 20 ++++++++++++++++++++
src/qemu/qemu_command.c | 14 +++++++++++++-
src/qemu/qemu_conf.c | 3 +++
src/qemu/qemu_conf.h | 1 +
src/util/virstoragefile.h | 2 ++
.../qemuargv2xml-disk-drive-network-gluster.args | 7 ++++---
.../qemuxml2argv-disk-drive-network-gluster.args | 12 ++++++------
7 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index e4c2aae..a6cdcf3 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -621,3 +621,23 @@
# rollover when a size limit is hit.
#
#stdio_handler = "logd"
+
+# Qemu gluster libgfapi log level, debug levels are 0-9, with 9 being the
+# most verbose, and 0 representing no debugging output.
+#
+# The current logging levels defined in the gluster GFAPI are:
+#
+# 0 - None
+# 1 - Emergency
+# 2 - Alert
+# 3 - Critical
+# 4 - Error
+# 5 - Warning
+# 6 - Notice
+# 7 - Info
+# 8 - Debug
+# 9 - Trace
+#
+# Defaults to 4
+#
+# glusterfs_debug_level = 9
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3a61863..c333795 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1383,6 +1383,11 @@ qemuBuildDriveSourceStr(virDomainDiskDefPtr disk,
}
virBufferAddLit(buf, ",");
+ if (disk->src &&
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
+ virBufferAsprintf(buf, "file.debug=%d,", disk->src->debug_level);
+ }
+
if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
/* NB: If libvirt starts using the more modern option based
* syntax to build the command line (e.g., "-drive driver=rbd,
@@ -2177,6 +2182,7 @@ qemuBuildDriveDevStr(const virDomainDef *def,
static int
qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
+ virQEMUDriverConfigPtr cfg,
const virDomainDef *def,
virQEMUCapsPtr qemuCaps)
{
@@ -2255,6 +2261,12 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
virCommandAddArg(cmd, "-drive");
+ if (disk->src &&
+ disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
+ if (cfg->glusterfsDebugLevel)
+ disk->src->debug_level = cfg->glusterfsDebugLevel;
+ }
+
if (!(optstr = qemuBuildDriveStr(disk, driveBoot, qemuCaps)))
return -1;
virCommandAddArg(cmd, optstr);
@@ -9613,7 +9625,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildHubCommandLine(cmd, def, qemuCaps) < 0)
goto error;
- if (qemuBuildDiskDriveCommandLine(cmd, def, qemuCaps) < 0)
+ if (qemuBuildDiskDriveCommandLine(cmd, cfg, def, qemuCaps) < 0)
goto error;
if (qemuBuildFSDevCommandLine(cmd, def, qemuCaps) < 0)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index dad8334..ff2b58e 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -311,6 +311,7 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
cfg->seccompSandbox = -1;
cfg->logTimestamp = true;
+ cfg->glusterfsDebugLevel = 4;
cfg->stdioLogD = true;
#ifdef DEFAULT_LOADER_NVRAM
@@ -780,6 +781,8 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
goto cleanup;
}
}
+ if (virConfGetValueUInt(conf, "glusterfs_debug_level", &cfg->glusterfsDebugLevel) < 0)
+ goto cleanup;
ret = 0;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index d8232cc..89d046d 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -190,6 +190,7 @@ struct _virQEMUDriverConfig {
virFirmwarePtr *firmwares;
size_t nfirmwares;
+ unsigned int glusterfsDebugLevel;
};
/* Main driver state */
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index 3d09468..9f3add3 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -237,6 +237,8 @@ struct _virStorageSource {
virStorageAuthDefPtr auth;
virStorageEncryptionPtr encryption;
+ unsigned int debug_level;
+
char *driverName;
int format; /* virStorageFileFormat in domain backing chains, but
* pool-specific enum for storage volumes */
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args b/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args
index f560308..deec7a7 100644
--- a/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args
+++ b/tests/qemuargv2xmldata/qemuargv2xml-disk-drive-network-gluster.args
@@ -16,9 +16,10 @@ QEMU_AUDIO_DRV=none \
-no-acpi \
-boot c \
-usb \
--drive file=gluster://example.org:6000/Volume1/Image,format=raw,if=virtio \
--drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,format=raw,\
-if=virtio' \
+-drive file=gluster://example.org:6000/Volume1/Image,file.debug=4,format=raw,\
+if=virtio \
+-drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,file.debug=4,\
+format=raw,if=virtio' \
-net none \
-serial none \
-parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
index 634ed75..cd5294e 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-gluster.args
@@ -17,18 +17,18 @@ QEMU_AUDIO_DRV=none \
-no-acpi \
-boot c \
-usb \
--drive file=gluster://example.org:6000/Volume1/Image,format=raw,if=none,\
-id=drive-virtio-disk0 \
+-drive file=gluster://example.org:6000/Volume1/Image,file.debug=4,format=raw,\
+if=none,id=drive-virtio-disk0 \
-device virtio-blk-pci,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,\
id=virtio-disk0 \
--drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,format=raw,\
-if=none,id=drive-virtio-disk1' \
+-drive 'file=gluster+unix:///Volume2/Image?socket=/path/to/sock,file.debug=4,\
+format=raw,if=none,id=drive-virtio-disk1' \
-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk1,\
id=virtio-disk1 \
-drive file.driver=gluster,file.volume=Volume3,file.path=/Image.qcow2,\
file.server.0.type=tcp,file.server.0.host=example.org,file.server.0.port=6000,\
file.server.1.type=tcp,file.server.1.host=example.org,file.server.1.port=24007,\
-file.server.2.type=unix,file.server.2.socket=/path/to/sock,format=qcow2,\
-if=none,id=drive-virtio-disk2 \
+file.server.2.type=unix,file.server.2.socket=/path/to/sock,file.debug=4,\
+format=qcow2,if=none,id=drive-virtio-disk2 \
-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk2,\
id=virtio-disk2
--
2.7.4
1
0
Added few functions into test driver.
Tomáš Ryšavý (8):
virhostcpu: Expose virHostCPUStatsAssign
test driver: Replaced num by a constant.
test driver: Implement virConnectGetSysinfo.
test driver: Implement virConnectGetType.
test driver: Implement testNodeGetCPUStats
test driver: Implement testNodeGetFreeMemory
test driver: added pages sizes into XML into test driver.
test driver: Implement testNodeGetFreePages.
src/libvirt_private.syms | 1 +
src/test/test_driver.c | 148 +++++++++++++++++++++++++++++++++++++++++++++--
src/util/virhostcpu.c | 2 +-
src/util/virhostcpu.h | 4 ++
4 files changed, 148 insertions(+), 7 deletions(-)
--
2.9.3
3
15
[libvirt] [PATCH v4] virsh: use virConnectGetDomainCapabilities with maxvcpus
by Shivaprasad G Bhat 15 Sep '16
by Shivaprasad G Bhat 15 Sep '16
15 Sep '16
virsh maxvcpus --type kvm output is useless on PPC. Also, in
commit e6806d79 we documented not rely on virConnectGetMaxVcpus
output. Fix the maxvcpus to use virConnectGetDomainCapabilities
now to make it useful. The call is made to use the default emulator
binary and to check for the host machine and arch which is what the
command intends to show anyway.
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
---
tools/virsh-host.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index 57f0c0e..dbdf23d 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -606,18 +606,46 @@ static bool
cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
{
const char *type = NULL;
- int vcpus;
+ int vcpus = -1;
+ char *caps = NULL;
+ const unsigned int flags = 0; /* No flags so far */
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr ctxt = NULL;
virshControlPtr priv = ctl->privData;
if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
return false;
- if ((vcpus = virConnectGetMaxVcpus(priv->conn, type)) < 0)
+ caps = virConnectGetDomainCapabilities(priv->conn, NULL, NULL, NULL, type, flags);
+ if (!caps) {
+ if (last_error && last_error->code != VIR_ERR_NO_SUPPORT)
+ return false;
+
+ vshResetLibvirtError();
+ goto fallback;
+ }
+
+ xml = virXMLParseStringCtxt(caps, _("(domainCapabilities)"), &ctxt);
+ if (!xml) {
+ VIR_FREE(caps);
return false;
+ }
- vshPrint(ctl, "%d\n", vcpus);
+ virXPathInt("string(./vcpu[1]/@max)", ctxt, &vcpus);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ VIR_FREE(caps);
+ if (vcpus < 0)
+ goto fallback;
+
+ exit:
+ vshPrint(ctl, "%d\n", vcpus);
return true;
+ fallback:
+ if ((vcpus = virConnectGetMaxVcpus(priv->conn, type)) < 0)
+ return false;
+ goto exit;
}
/*
2
3
Commit ca32929908bbc94116493ad8915e7cd7ae0f57d5 added function
virTestCompareToFile(), but forgot to use a fixedcontent value for the
actual comparison. That lead to VIR_TEST_DEBUG=1 showing (for some
tests) all the actual output from the first error to the end of the
string due to the difference being an endline in the end.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
Pushed as 'trivial'.
tests/testutils.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/testutils.c b/tests/testutils.c
index 8ea6ab82ad5a..f87628edee68 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -709,7 +709,7 @@ virTestCompareToFile(const char *strcontent,
filecontent)) {
virTestDifferenceFull(stderr,
filecontent, filename,
- strcontent, NULL);
+ fixedcontent, NULL);
goto failure;
}
--
2.10.0
1
0
Re: [libvirt] [PATCH 8/8] fspools: docs and tests for fspool directory backend
by Olga Krishtal 15 Sep '16
by Olga Krishtal 15 Sep '16
15 Sep '16
Hello again.
Please, drop the commit message for this patch.
Use the following one:
Added XML 2 XML tests for fspool and item.
________________________________
From: Olga Krishtal
Sent: Thursday, September 15, 2016 10:39:01 AM
To: openstack-devel
Cc: Maxim Nestratov; Nikolay Shirokovskiy
Subject: Re: [PATCH 8/8] fspools: docs and tests for fspool directory backend
On 26/08/16 17:17, Olga Krishtal wrote:
Pleas, drop the commit message, test is present for both: item and fspool.
> At the moment only pool test is implemented.
> You need to inplement item test.
>
> Signed-off-by: Olga Krishtal <okrishtal(a)virtuozzo.com>
> ---
> docs/schemas/fsitem.rng | 69 ++++++++++++++
> docs/schemas/fspool.rng | 83 ++++++++++++++++
> tests/fsitemxml2xmltest.c | 105 +++++++++++++++++++++
> .../dir-missing-target-path-invalid.xml | 12 +++
> tests/fspoolxml2xmlin/fspool-dir.xml | 17 ++++
> tests/fspoolxml2xmlout/fspool-dir.xml | 17 ++++
> tests/fspoolxml2xmltest.c | 82 ++++++++++++++++
> 7 files changed, 385 insertions(+)
> create mode 100644 docs/schemas/fsitem.rng
> create mode 100644 docs/schemas/fspool.rng
> create mode 100644 tests/fsitemxml2xmltest.c
> create mode 100644 tests/fspoolschemadata/dir-missing-target-path-invalid.xml
> create mode 100644 tests/fspoolxml2xmlin/fspool-dir.xml
> create mode 100644 tests/fspoolxml2xmlout/fspool-dir.xml
> create mode 100644 tests/fspoolxml2xmltest.c
>
> diff --git a/docs/schemas/fsitem.rng b/docs/schemas/fsitem.rng
> new file mode 100644
> index 0000000..a41659c
> --- /dev/null
> +++ b/docs/schemas/fsitem.rng
> @@ -0,0 +1,69 @@
> +<?xml version="1.0"?>
> +<!-- A Relax NG schema for the libvirt storage volume XML format -->
> +<grammar xmlns="http://relaxng.org/ns/structure/1.0"
> + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
> + <include href='basictypes.rng'/>
> + <start>
> + <ref name='vol'/>
> + </start>
> +
> + <include href='storagecommon.rng'/>
> +
> +
> + <define name='item'>
> + <element name='fsitem'>
> + <optional>
> + <attribute name='type'>
> + <value>dir</value>
> + </attribute>
> + </optional>
> + <interleave>
> + <element name='name'>
> + <ref name='volName'/>
> + </element>
> + <optional>
> + <element name='key'>
> + <text/>
> + </element>
> + </optional>
> + <ref name='sizing'/>
> + <ref name='target'/>
> + </interleave>
> + </element>
> + </define>
> +
> + <define name='sizing'>
> + <interleave>
> + <optional>
> + <element name='capacity'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + <optional>
> + <element name='allocation'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + </interleave>
> + </define>
> +
> + <define name='target'>
> + <element name='target'>
> + <interleave>
> + <optional>
> + <element name='path'>
> + <choice>
> + <data type='anyURI'/>
> + <ref name='absFilePath'/>
> + </choice>
> + </element>
> + </optional>
> + <ref name='permissions'/>
> + <optional>
> + <ref name='fileFormatFeatures'/>
> + </optional>
> + </interleave>
> + </element>
> + </define>
> +
> +</grammar>
> diff --git a/docs/schemas/fspool.rng b/docs/schemas/fspool.rng
> new file mode 100644
> index 0000000..132b65c
> --- /dev/null
> +++ b/docs/schemas/fspool.rng
> @@ -0,0 +1,83 @@
> +<?xml version="1.0"?>
> +<!-- A Relax NG schema for the libvirt storage pool XML format -->
> +<grammar xmlns="http://relaxng.org/ns/structure/1.0"
> + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
> + <include href='basictypes.rng'/>
> + <include href='storagecommon.rng'/>
> + <start>
> + <ref name='pool'/>
> + </start>
> +
> +
> + <define name='fspool'>
> + <element name='fspool'>
> + <choice>
> + <ref name='fspooldir'/>
> + </choice>
> + </element>
> + </define>
> +
> + <define name='fspooldir'>
> + <attribute name='type'>
> + <value>dir</value>
> + </attribute>
> + <interleave>
> + <ref name='commonmetadata'/>
> + <ref name='sizing'/>
> + <ref name='sourcedir'/>
> + <ref name='target'/>
> + </interleave>
> + </define>
> +
> + <define name='commonmetadata'>
> + <interleave>
> + <element name='name'>
> + <ref name='genericName'/>
> + </element>
> + <optional>
> + <element name='uuid'>
> + <ref name='UUID'/>
> + </element>
> + </optional>
> + </interleave>
> + </define>
> +
> + <define name='sizing'>
> + <interleave>
> + <optional>
> + <element name='capacity'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + <optional>
> + <element name='allocation'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + <optional>
> + <element name='available'>
> + <ref name='scaledInteger'/>
> + </element>
> + </optional>
> + </interleave>
> + </define>
> +
> + <define name='target'>
> + <element name='target'>
> + <interleave>
> + <element name='path'>
> + <ref name='absFilePath'/>
> + </element>
> + <ref name='permissions'/>
> + </interleave>
> + </element>
> + </define>
> +
> + <define name='sourcedir'>
> + <optional>
> + <element name='source'>
> + </element>
> + </optional>
> + </define>
> +
> +</grammar>
> diff --git a/tests/fsitemxml2xmltest.c b/tests/fsitemxml2xmltest.c
> new file mode 100644
> index 0000000..87a24e3
> --- /dev/null
> +++ b/tests/fsitemxml2xmltest.c
> @@ -0,0 +1,105 @@
> +#include <config.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include <sys/types.h>
> +#include <fcntl.h>
> +
> +#include "internal.h"
> +#include "testutils.h"
> +#include "storage_conf.h"
> +#include "testutilsqemu.h"
> +#include "virstring.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +static int
> +testCompareXMLToXMLFiles(const char *poolxml, const char *inxml,
> + const char *outxml, unsigned int flags)
> +{
> + char *actual = NULL;
> + int ret = -1;
> + virFSPoolDefPtr pool = NULL;
> + virFSItemDefPtr dev = NULL;
> +
> + if (!(pool = virFSPoolDefParseFile(poolxml)))
> + goto fail;
> +
> + if (!(dev = virFSItemDefParseFile(pool, inxml, flags)))
> + goto fail;
> +
> + if (!(actual = virFSItemDefFormat(pool, dev)))
> + goto fail;
> +
> + if (virTestCompareToFile(actual, outxml) < 0)
> + goto fail;
> +
> + ret = 0;
> +
> + fail:
> + VIR_FREE(actual);
> + virFSPoolDefFree(pool);
> + virFSItemDefFree(dev);
> + return ret;
> +}
> +
> +struct testInfo {
> + const char *pool;
> + const char *name;
> + unsigned int flags;
> +};
> +
> +static int
> +testCompareXMLToXMLHelper(const void *data)
> +{
> + int result = -1;
> + const struct testInfo *info = data;
> + char *poolxml = NULL;
> + char *inxml = NULL;
> + char *outxml = NULL;
> +
> + if (virAsprintf(&poolxml, "%s/storagepoolxml2xmlin/%s.xml",
> + abs_srcdir, info->pool) < 0 ||
> + virAsprintf(&inxml, "%s/storagevolxml2xmlin/%s.xml",
> + abs_srcdir, info->name) < 0 ||
> + virAsprintf(&outxml, "%s/storagevolxml2xmlout/%s.xml",
> + abs_srcdir, info->name) < 0) {
> + goto cleanup;
> + }
> +
> + result = testCompareXMLToXMLFiles(poolxml, inxml, outxml, info->flags);
> +
> + cleanup:
> + VIR_FREE(poolxml);
> + VIR_FREE(inxml);
> + VIR_FREE(outxml);
> +
> + return result;
> +}
> +
> +
> +static int
> +mymain(void)
> +{
> + int ret = 0;
> +
> +#define DO_TEST_FULL(pool, name, flags) \
> + do { \
> + struct testInfo info = { pool, name, flags }; \
> + if (virTestRun("FS Item XML-2-XML " name, \
> + testCompareXMLToXMLHelper, &info) < 0) \
> + ret = -1; \
> + } \
> + while (0);
> +
> +#define DO_TEST(pool, name) DO_TEST_FULL(pool, name, 0)
> +
> + DO_TEST("pool-dir", "vol-file");
> +
> + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +VIRT_TEST_MAIN(mymain)
> diff --git a/tests/fspoolschemadata/dir-missing-target-path-invalid.xml b/tests/fspoolschemadata/dir-missing-target-path-invalid.xml
> new file mode 100644
> index 0000000..a52bf49
> --- /dev/null
> +++ b/tests/fspoolschemadata/dir-missing-target-path-invalid.xml
> @@ -0,0 +1,12 @@
> +<fspool type='dir'>
> + <name>test</name>
> + <source>
> + </source>
> + <target>
> + <permissions>
> + <mode>0700</mode>
> + <owner>-1</owner>
> + <group>-1</group>
> + </permissions>
> + </target>
> +</fspool>
> diff --git a/tests/fspoolxml2xmlin/fspool-dir.xml b/tests/fspoolxml2xmlin/fspool-dir.xml
> new file mode 100644
> index 0000000..a3a1639
> --- /dev/null
> +++ b/tests/fspoolxml2xmlin/fspool-dir.xml
> @@ -0,0 +1,17 @@
> +<fspool type='dir'>
> + <name>virtfs</name>
> + <uuid>5584ee21-db40-4e98-980e-44802c47b62f</uuid>
> + <capacity unit='bytes'>0</capacity>
> + <allocation unit='bytes'>0</allocation>
> + <available unit='bytes'>0</available>
> + <source>
> + </source>
> + <target>
> + <path>///var/////lib/libvirt/fs//</path>
> + <permissions>
> + <mode>0700</mode>
> + <owner>-1</owner>
> + <group>-1</group>
> + </permissions>
> + </target>
> +</fspool>
> diff --git a/tests/fspoolxml2xmlout/fspool-dir.xml b/tests/fspoolxml2xmlout/fspool-dir.xml
> new file mode 100644
> index 0000000..30aca89
> --- /dev/null
> +++ b/tests/fspoolxml2xmlout/fspool-dir.xml
> @@ -0,0 +1,17 @@
> +<fspool type='dir'>
> + <name>virtfs</name>
> + <uuid> 5584ee21-db40-4e98-980e-44802c47b62f</uuid>
> + <capacity unit='bytes'>0</capacity>
> + <allocation unit='bytes'>0</allocation>
> + <available unit='bytes'>0</available>
> + <source>
> + </source>
> + <target>
> + <path>/var/lib/libvirt/fs</path>
> + <permissions>
> + <mode>0700</mode>
> + <owner>-1</owner>
> + <group>-1</group>
> + </permissions>
> + </target>
> +</fspool>
> diff --git a/tests/fspoolxml2xmltest.c b/tests/fspoolxml2xmltest.c
> new file mode 100644
> index 0000000..b66e959
> --- /dev/null
> +++ b/tests/fspoolxml2xmltest.c
> @@ -0,0 +1,82 @@
> +#include <config.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +#include <sys/types.h>
> +#include <fcntl.h>
> +
> +#include "internal.h"
> +#include "testutils.h"
> +#include "fs_conf.h"
> +#include "testutilsqemu.h"
> +#include "virstring.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +static int
> +testCompareXMLToXMLFiles(const char *inxml, const char *outxml)
> +{
> + char *actual = NULL;
> + int ret = -1;
> + virFSPoolDefPtr dev = NULL;
> +
> + if (!(dev = virFSPoolDefParseFile(inxml)))
> + goto fail;
> +
> + if (!(actual = virFSPoolDefFormat(dev)))
> + goto fail;
> +
> + if (virTestCompareToFile(actual, outxml) < 0)
> + goto fail;
> +
> + ret = 0;
> +
> + fail:
> + VIR_FREE(actual);
> + virFSPoolDefFree(dev);
> + return ret;
> +}
> +
> +static int
> +testCompareXMLToXMLHelper(const void *data)
> +{
> + int result = -1;
> + char *inxml = NULL;
> + char *outxml = NULL;
> +
> + if (virAsprintf(&inxml, "%s/fspoolxml2xmlin/%s.xml",
> + abs_srcdir, (const char*)data) < 0 ||
> + virAsprintf(&outxml, "%s/fspoolxml2xmlout/%s.xml",
> + abs_srcdir, (const char*)data) < 0) {
> + goto cleanup;
> + }
> +
> + result = testCompareXMLToXMLFiles(inxml, outxml);
> +
> + cleanup:
> + VIR_FREE(inxml);
> + VIR_FREE(outxml);
> +
> + return result;
> +}
> +
> +static int
> +mymain(void)
> +{
> + int ret = 0;
> +
> +#define DO_TEST(name) \
> + if (virTestRun("FS Pool XML-2-XML " name, \
> + testCompareXMLToXMLHelper, (name)) < 0) \
> + ret = -1
> +
> + DO_TEST("pool-dir");
> +#endif
> +
> + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +VIRT_TEST_MAIN(mymain)
1
0
15 Sep '16
Fedora rawhide builds of libvirt.git at commit d53fa838^ failed
due to the new glibc 2.25 deprecation warning for use of major()
from just <sys/types.h>; I also found that the same warning is
provoked by gnulib's mountlist module. Libvirt commit d53fa838
was a temporary hack to work around the problem, and I will be
reverting that and updating to newer gnulib once this goes in.
I've tested that libvirt on Fedora rawhide with d53fa838 reverted
and gnulib updated to this commit was once again able to build.
Comments welcome, particularly for my choice of wording in
documentation changes. The final push will differ slightly from
this, especially if the autoconf patch going in first changes
slightly due to review there, but this should give a good idea
of the fix.
Eric Blake (2):
mountlist: include sysmacros.h for glibc
sys_types: avoid glibc 2.25 warnings about major()
ChangeLog | 15 +++++++++++++++
doc/glibc-functions/gnu_dev_major.texi | 4 ++++
doc/glibc-functions/gnu_dev_makedev.texi | 4 ++++
doc/glibc-functions/gnu_dev_minor.texi | 4 ++++
doc/posix-headers/sys_types.texi | 6 ++++++
lib/mountlist.c | 6 ++++++
m4/mountlist.m4 | 3 ++-
m4/sys_types_h.m4 | 27 ++++++++++++++++++++++++++-
8 files changed, 67 insertions(+), 2 deletions(-)
--
2.7.4
1
2
14 Sep '16
From: Chen Hanxiao <chenhanxiao(a)gmail.com>
We check compress prog in qemuCompressProgramAvailable,
then check it again in virExec.
This path will pass compress prog's path directly.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)gmail.com>
---
src/qemu/qemu_driver.c | 42 ++++++++++++++++++++++++++----------------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 97e2ffc..9f4e593 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3037,6 +3037,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
const char *path,
const char *domXML,
int compressed,
+ const char *compressed_path,
bool was_running,
unsigned int flags,
qemuDomainAsyncJob asyncJob)
@@ -3084,7 +3085,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
goto cleanup;
/* Perform the migration */
- if (qemuMigrationToFile(driver, vm, fd, qemuCompressProgramName(compressed),
+ if (qemuMigrationToFile(driver, vm, fd, compressed_path,
asyncJob) < 0)
goto cleanup;
@@ -3137,7 +3138,8 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
static int
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
virDomainObjPtr vm, const char *path,
- int compressed, const char *xmlin, unsigned int flags)
+ int compressed, const char *compressed_path,
+ const char *xmlin, unsigned int flags)
{
char *xml = NULL;
bool was_running = false;
@@ -3209,7 +3211,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
goto endjob;
}
- ret = qemuDomainSaveMemory(driver, vm, path, xml, compressed,
+ ret = qemuDomainSaveMemory(driver, vm, path, xml, compressed, compressed_path,
was_running, flags, QEMU_ASYNC_JOB_SAVE);
if (ret < 0)
goto endjob;
@@ -3250,17 +3252,16 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
/* Returns true if a compression program is available in PATH */
static bool
-qemuCompressProgramAvailable(virQEMUSaveFormat compress)
+qemuCompressProgramAvailable(virQEMUSaveFormat compress, char **compressed_path)
{
- char *path;
-
- if (compress == QEMU_SAVE_FORMAT_RAW)
+ if (compress == QEMU_SAVE_FORMAT_RAW) {
+ *compressed_path = NULL;
return true;
+ }
- if (!(path = virFindFileInPath(qemuSaveCompressionTypeToString(compress))))
+ if (!(*compressed_path = virFindFileInPath(qemuSaveCompressionTypeToString(compress))))
return false;
- VIR_FREE(path);
return true;
}
@@ -3270,6 +3271,7 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
{
virQEMUDriverPtr driver = dom->conn->privateData;
int compressed = QEMU_SAVE_FORMAT_RAW;
+ char *compressed_path = NULL;
int ret = -1;
virDomainObjPtr vm = NULL;
virQEMUDriverConfigPtr cfg = NULL;
@@ -3287,7 +3289,7 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
"in configuration file"));
goto cleanup;
}
- if (!qemuCompressProgramAvailable(compressed)) {
+ if (!qemuCompressProgramAvailable(compressed, &compressed_path)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Compression program for image format "
"in configuration file isn't available"));
@@ -3308,11 +3310,12 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
}
ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
- dxml, flags);
+ compressed_path, dxml, flags);
cleanup:
virDomainObjEndAPI(&vm);
virObjectUnref(cfg);
+ VIR_FREE(compressed_path);
return ret;
}
@@ -3343,6 +3346,7 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
virQEMUDriverPtr driver = dom->conn->privateData;
virQEMUDriverConfigPtr cfg = NULL;
int compressed = QEMU_SAVE_FORMAT_RAW;
+ char *compressed_path = NULL;
virDomainObjPtr vm;
char *name = NULL;
int ret = -1;
@@ -3377,7 +3381,7 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
"in configuration file"));
goto cleanup;
}
- if (!qemuCompressProgramAvailable(compressed)) {
+ if (!qemuCompressProgramAvailable(compressed, &compressed_path)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Compression program for image format "
"in configuration file isn't available"));
@@ -3391,13 +3395,14 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
VIR_INFO("Saving state of domain '%s' to '%s'", vm->def->name, name);
ret = qemuDomainSaveInternal(driver, dom, vm, name,
- compressed, NULL, flags);
+ compressed, compressed_path, NULL, flags);
if (ret == 0)
vm->hasManagedSave = true;
cleanup:
virDomainObjEndAPI(&vm);
VIR_FREE(name);
+ VIR_FREE(compressed_path);
virObjectUnref(cfg);
return ret;
@@ -3617,6 +3622,7 @@ static virQEMUSaveFormat
getCompressionType(virQEMUDriverPtr driver)
{
int ret = QEMU_SAVE_FORMAT_RAW;
+ char *compressed_path = NULL;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
/*
@@ -3634,7 +3640,7 @@ getCompressionType(virQEMUDriverPtr driver)
ret = QEMU_SAVE_FORMAT_RAW;
goto cleanup;
}
- if (!qemuCompressProgramAvailable(ret)) {
+ if (!qemuCompressProgramAvailable(ret, &compressed_path)) {
VIR_WARN("%s", _("Compression program for dump image format "
"in configuration file isn't available, "
"using raw"));
@@ -3644,6 +3650,7 @@ getCompressionType(virQEMUDriverPtr driver)
}
cleanup:
virObjectUnref(cfg);
+ VIR_FREE(compressed_path);
return ret;
}
@@ -14308,6 +14315,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
bool pmsuspended = false;
virQEMUDriverConfigPtr cfg = NULL;
int compressed = QEMU_SAVE_FORMAT_RAW;
+ char *compressed_path = NULL;
/* If quiesce was requested, then issue a freeze command, and a
* counterpart thaw command when it is actually sent to agent.
@@ -14377,7 +14385,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
goto cleanup;
}
- if (!qemuCompressProgramAvailable(compressed)) {
+ if (!qemuCompressProgramAvailable(compressed, &compressed_path)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Compression program for image format "
"in configuration file isn't available"));
@@ -14389,7 +14397,8 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
goto cleanup;
if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file,
- xml, compressed, resume, 0,
+ xml, compressed, compressed_path,
+ resume, 0,
QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
goto cleanup;
@@ -14459,6 +14468,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
}
VIR_FREE(xml);
+ VIR_FREE(compressed_path);
virObjectUnref(cfg);
if (memory_unlink && ret < 0)
unlink(snap->def->file);
--
1.8.3.1
2
4
14 Sep '16
I've realized we do no testing of virt-admin yet while reviewing Erik's
patches.
Michal Privoznik (2):
virsh: Move cmdSelfTest to vsh
tests: Self test virt-admin
.gitignore | 1 +
tests/Makefile.am | 1 +
tests/virsh-self-test | 21 ++++++++++++++++-----
tests/virt-admin-self-test | 1 +
tools/virsh.c | 45 +--------------------------------------------
tools/virt-admin.c | 1 +
tools/vsh.c | 38 ++++++++++++++++++++++++++++++++++++++
tools/vsh.h | 11 +++++++++++
8 files changed, 70 insertions(+), 49 deletions(-)
create mode 120000 tests/virt-admin-self-test
--
2.8.4
2
7
[libvirt] [libvirt-perl PATCH 0/2] Updates to support recent upstream changes
by John Ferlan 14 Sep '16
by John Ferlan 14 Sep '16
14 Sep '16
Couple of patches to allow build/test to work with upstream top
John Ferlan (2):
Add support for VIR_SECRET_USAGE_TYPE_TLS
Add support for ERR_AGENT_UNSYNCED
Changes | 2 ++
Virt.xs | 2 ++
lib/Sys/Virt/Error.pm | 4 ++++
lib/Sys/Virt/Secret.pm | 7 +++++++
4 files changed, 15 insertions(+)
--
2.7.4
2
4
There's been a discussion recently (even here on the list [1])
that Nova is sometimes unable to fetch block job stats properly.
Basically, we may report job.cur == job.end == 0 in some cases
tricking Nova into thinking job is done when in fact it hasn't
even started yet.
Michal Privoznik (2):
qemuDomainGetBlockJobInfo: Move info translation into separate func
virDomainGetBlockJobInfo: Fix corner case when qemu reports no info
src/libvirt-domain.c | 7 ++++++
src/qemu/qemu_driver.c | 58 ++++++++++++++++++++++++++++++++++++--------------
2 files changed, 49 insertions(+), 16 deletions(-)
--
2.8.4
4
11
[libvirt] [PATCH 0/4] Fix incorrect vcpu data refresh on daemon restart after vcpu hotplug
by Peter Krempa 14 Sep '16
by Peter Krempa 14 Sep '16
14 Sep '16
See patches 3 and 4 for explanation.
Peter Krempa (4):
qemu: monitor: Use a more obvious iterator name
qemu: monitor: qemuMonitorGetCPUInfoHotplug: Add iterator 'anycpu'
qemu: monitor: Add vcpu state information to monitor data
qemu: domain: Don't infer vcpu state
src/qemu/qemu_domain.c | 14 +++---
src/qemu/qemu_monitor.c | 51 ++++++++++++++--------
src/qemu/qemu_monitor.h | 4 ++
.../qemumonitorjson-cpuinfo-ppc64-basic.data | 48 ++++++++++++++++++++
.../qemumonitorjson-cpuinfo-ppc64-hotplug-1.data | 48 ++++++++++++++++++++
.../qemumonitorjson-cpuinfo-ppc64-hotplug-2.data | 48 ++++++++++++++++++++
.../qemumonitorjson-cpuinfo-ppc64-hotplug-4.data | 48 ++++++++++++++++++++
.../qemumonitorjson-cpuinfo-ppc64-no-threads.data | 32 ++++++++++++++
...emumonitorjson-cpuinfo-x86-basic-pluggable.data | 16 +++++++
.../qemumonitorjson-cpuinfo-x86-full.data | 22 ++++++++++
tests/qemumonitorjsontest.c | 3 ++
11 files changed, 306 insertions(+), 28 deletions(-)
--
2.10.0
3
11
[libvirt] [PATCH v2 0/3] Introduce aliases for virt-admin's srv-* commands
by Erik Skultety 14 Sep '16
by Erik Skultety 14 Sep '16
14 Sep '16
the original version:
https://www.redhat.com/archives/libvir-list/2016-September/msg00312.html
since v1:
- tweaked the virsh-self-test so that it also checks the aliased commands
instead of skipping them (since there was a good reason for that before the
changes this series introduces)
- patches 2-3 remained untouched
Erik Skultety (3):
virt-admin: Tweak command parsing logic so that aliases point to new
commands
virt-admin: Add some command aliases to provide syntax sugar over ugly
commands
virt-admin: Replace the (now) aliases with new command names in the
man page
tools/virsh-nodedev.c | 6 ++----
tools/virsh.c | 10 ++++++----
tools/virsh.pod | 2 --
tools/virt-admin.c | 24 ++++++++++++++++++++++++
tools/virt-admin.pod | 30 +++++++++++++++---------------
tools/vsh.c | 6 ++++++
tools/vsh.h | 1 +
7 files changed, 54 insertions(+), 25 deletions(-)
--
2.5.5
1
4
14 Sep '16
See patch 2.
Peter Krempa (2):
util: numa: Remove impossible error handling
numa: Rename virNumaGetHostNodeset and make it return only nodes with
memory
src/libvirt_private.syms | 2 +-
src/qemu/qemu_cgroup.c | 4 ++--
src/util/virnuma.c | 18 +++++++++++-------
src/util/virnuma.h | 2 +-
4 files changed, 15 insertions(+), 11 deletions(-)
--
2.10.0
2
3
[adding libvirt list, as this is what sparked my investigations so far
today]
On 09/13/2016 04:36 PM, Eric Blake wrote:
> One other possibility that distros can do is to prime a config.site
> file, with $ac_cv_header_sys_types_h_makedev=no, to forcefully bypass
> the configure check that is normally done where <sys/types.h> would
> warn. It has to be in config.site, because non-glibc systems do not
> want to do that.
Okay, I have confirmed that this prime-the-cache idea DOES work, using
libvirt.git commit 419bc8cf (one commit prior to d53fa838 which
installed a hack into libvirt to force the use of -Werror for the
duration of AC_HEADER_MAJOR [1]). By itself, './configure' succeeds but
leaves MAJOR_IN_SYSMACROS undefined, which results in a build failure
later in libvirt; but when run as './configure
ac_cv_header_sys_types_h_makedev=no', MAJOR_IN_SYSMACROS gets defined
and the build succeeds.
I want to remove the libvirt hack (not all compilers understand -Werror,
even if libvirt is only ever built by gcc or clang), and my experiment
was enough to prove that:
1. distros that provide a config.site file can use this file to avoid
the problem, even for packages that have not yet rebuilt with a
new-enough autoconf to fix the issue
2. autoconf and gnulib should indeed be fixed to probe for
<sys/sysmacros.h> _prior_ to probing for whether makedev() exists in
<sys/type.h>, rather than the 2.69 logic of only checking for
<sys/sysmacros.h> if makedev() was not found earlier.
Of course, the libvirt hack should not be reverted until autoconf and
gnulib have the final solution in place.
>
> Meanwhile, even without an autoconf release scheduled, I am currently
> working on patching the existing autoconf macro and documentation to
> match the current situation. It sounds to me like we want the following
> logic:
>
> If <sys/sysmacros.h> exists and defines major(), use that,
> else if <sys/mkdev.h> exists, use that,
> else if <sys/types.h> defines major(), use that,
> else not available
The current autoconf code assumes that if <sys/sysmacros.h> exists, then
it defines major()/minor()/makedev(); I think that assumption is still
safe. Where autoconf was wrong was that it was not even probing for the
existence of <sys/sysmacros.h> if it found that <sys/types.h> was enough
to pollute the namespace with the three macros.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
1
1
[libvirt] [PATCH] storage_backend_rbd: continue searching when failing in rbd_diff_iterate
by Chen Hanxiao 13 Sep '16
by Chen Hanxiao 13 Sep '16
13 Sep '16
From: Chen Hanxiao <chenhanxiao(a)gmail.com>
We try to find a snapshot that had no different between
the current state of RBD image.
If we failed in rbd_diff_iterate, just continue for the
next search iteration.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)gmail.com>
---
src/storage/storage_backend_rbd.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
index 4dd4b24..2756c83 100644
--- a/src/storage/storage_backend_rbd.c
+++ b/src/storage/storage_backend_rbd.c
@@ -831,9 +831,10 @@ virStorageBackendRBDSnapshotFindNoDiff(rbd_image_t image,
#endif
if (r < 0) {
- virReportSystemError(-r, _("failed to iterate RBD snapshot %s@%s"),
- imgname, snaps[i].name);
- goto cleanup;
+ VIR_DEBUG("failed to iterate RBD snapshot %s@%s,"
+ " rbd_diff return %d",
+ imgname, snaps[i].name, r);
+ continue;
}
/* If diff is still set to zero we found a snapshot without deltas */
--
1.8.3.1
2
2
13 Sep '16
So, as suggested by Martin in [1], this series tweaks the command alias
handling logic, so that when creating alias, it is not necessary to duplicate
the original command's structure, thus creating a bit more noise. Instead,
the new format for an alias structure hints very clearly that it's just an
alias for a different command, while linking the alias with the original
command's data by using new element '.alias'.
[1] https://www.redhat.com/archives/libvir-list/2016-September/msg00129.html
Erik Skultety (4):
tests: fix incorrect status handling by virsh-self-test
virt-admin: Tweak command parsing logic so that aliases point to new
commands
virt-admin: Add some command aliases to provide syntax sugar over ugly
commands
virt-admin: Replace the (now) aliases with new command names in the
man page
tests/virsh-self-test | 2 +-
tools/virsh-nodedev.c | 6 ++----
tools/virsh.c | 3 ++-
tools/virt-admin.c | 24 ++++++++++++++++++++++++
tools/virt-admin.pod | 30 +++++++++++++++---------------
tools/vsh.c | 6 ++++++
tools/vsh.h | 1 +
7 files changed, 51 insertions(+), 21 deletions(-)
--
2.5.5
2
9
13 Sep '16
Thing is, in f3f15cc24 I'm trying to adapt libvirt to the newest
glibc where major()/minor()/makedev() are moved from sys/types.h
to sys/sysmacros.h. However, my commit back then expect autoconf
to be fixed too as we already use AC_HEADER_MAJOR to determine
which header file the functions are in, but because the header
files just trigger a warning and not a compile error, the
autoconf macro detects the bad header file.
This is just a workaround until autoconf macro is fixed.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
configure.ac | 3 +++
1 file changed, 3 insertions(+)
diff --git a/configure.ac b/configure.ac
index f6076bd..f322c4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,7 +144,10 @@ AC_TYPE_UID_T
dnl Support building Win32 DLLs (must appear *before* AM_PROG_LIBTOOL)
AC_LIBTOOL_WIN32_DLL
+old_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -Werror"
AC_HEADER_MAJOR
+CFLAGS=$old_CFLAGS
m4_ifndef([LT_INIT], [
AM_PROG_LIBTOOL
--
2.8.4
2
1
[libvirt] qemu: migration: shall we abort migration while the guest is rebooting?
by Zhangbo (Oscar) 13 Sep '16
by Zhangbo (Oscar) 13 Sep '16
13 Sep '16
Hi all:
Here's the steps we produce the problem:
1 reboot guest with the flag of VIR_DOMAIN_REBOOT_ACPI_POWER_BTN
2 sleep 1 second (so that the guest is still rebooting, although the API already returned.)
3 migrate the guest
The problem is that : the guest failed to migrate to the dest, and crashed on source side.
We don't bother to dig further into the problem, the root cause we think is that we migrate a guest while it's rebooting.
So, shall we
1 make the reboot JOB LOCK longer enough until the guest has already rebooted(got monitor message from qemu)?
2 let openstack do the mutex work ? (has openstack already done this?)
(I checked openstack codes, and found that openstack uses shutdown and create APIs rather than REBOOT to do the reboot work. So it seems that openstack doesn't take care of this problem nowadays. Am I right? --- see: nova/virt/libvirt/driver.py: _soft_reboot)
Thanks in advance.
Zhang Bo (Oscar)
2
4
[libvirt] [PATCH] qemu: Add missing 'p' to qemuCgrouEmulatorAllNodesRestore
by Peter Krempa 13 Sep '16
by Peter Krempa 13 Sep '16
13 Sep '16
---
Pushed as trivial.
src/qemu/qemu_cgroup.c | 6 +++---
src/qemu/qemu_cgroup.h | 2 +-
src/qemu/qemu_driver.c | 2 +-
src/qemu/qemu_process.c | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index e2b5bab..fe94613 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -1149,7 +1149,7 @@ qemuCgroupEmulatorAllNodesDataFree(qemuCgroupEmulatorAllNodesDataPtr data)
* Allows all NUMA nodes for the qemu emulator thread temporarily. This is
* necessary when hotplugging cpus since it requires memory allocated in the
* DMA region. Afterwards the operation can be reverted by
- * qemuCgrouEmulatorAllNodesRestore.
+ * qemuCgroupEmulatorAllNodesRestore.
*
* Returns 0 on success -1 on error
*/
@@ -1196,14 +1196,14 @@ qemuCgroupEmulatorAllNodesAllow(virCgroupPtr cgroup,
/**
- * qemuCgrouEmulatorAllNodesRestore:
+ * qemuCgroupEmulatorAllNodesRestore:
* @data: data structure created by qemuCgroupEmulatorAllNodesAllow
*
* Rolls back the setting done by qemuCgroupEmulatorAllNodesAllow and frees the
* associated data.
*/
void
-qemuCgrouEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data)
+qemuCgroupEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data)
{
virErrorPtr err;
diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h
index e6ebae0..623823e 100644
--- a/src/qemu/qemu_cgroup.h
+++ b/src/qemu/qemu_cgroup.h
@@ -66,6 +66,6 @@ struct _qemuCgroupEmulatorAllNodesData {
int qemuCgroupEmulatorAllNodesAllow(virCgroupPtr cgroup,
qemuCgroupEmulatorAllNodesDataPtr *data);
-void qemuCgrouEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data);
+void qemuCgroupEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesDataPtr data);
#endif /* __QEMU_CGROUP_H__ */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 12b84c4..dda82d3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4891,7 +4891,7 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
ret = 0;
cleanup:
- qemuCgrouEmulatorAllNodesRestore(emulatorCgroup);
+ qemuCgroupEmulatorAllNodesRestore(emulatorCgroup);
virBitmapFree(vcpumap);
return ret;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 7596579..cecd321 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4925,7 +4925,7 @@ qemuProcessSetupHotpluggableVcpus(virQEMUDriverPtr driver,
ret = 0;
cleanup:
- qemuCgrouEmulatorAllNodesRestore(emulatorCgroup);
+ qemuCgroupEmulatorAllNodesRestore(emulatorCgroup);
VIR_FREE(bootHotplug);
virJSONValueFree(vcpuprops);
return ret;
--
2.10.0
1
0
[libvirt] [PATCH] Make sure sys/types.h is included after sys/sysmacros.h
by Michal Privoznik 13 Sep '16
by Michal Privoznik 13 Sep '16
13 Sep '16
In the latest glibc, major() and minor() functions are marked as
deprecated (glibc commit dbab6577):
CC util/libvirt_util_la-vircgroup.lo
util/vircgroup.c: In function 'virCgroupGetBlockDevString':
util/vircgroup.c:768:5: error: '__major_from_sys_types' is deprecated:
In the GNU C Library, `major' is defined by <sys/sysmacros.h>.
For historical compatibility, it is currently defined by
<sys/types.h> as well, but we plan to remove this soon.
To use `major', include <sys/sysmacros.h> directly.
If you did not intend to use a system-defined macro `major',
you should #undef it after including <sys/types.h>.
[-Werror=deprecated-declarations]
if (virAsprintf(&ret, "%d:%d ", major(sb.st_rdev), minor(sb.st_rdev)) < 0)
^~
In file included from /usr/include/features.h:397:0,
from /usr/include/bits/libc-header-start.h:33,
from /usr/include/stdio.h:28,
from ../gnulib/lib/stdio.h:43,
from util/vircgroup.c:26:
/usr/include/sys/sysmacros.h:87:1: note: declared here
__SYSMACROS_DEFINE_MAJOR (__SYSMACROS_FST_IMPL_TEMPL)
^
Moreover, in the glibc commit, there's suggestion to keep
ordering of including of header files as implemented here.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
This still won't solve the build issue completely as AC_HEADER_MAJOR still
reports that major() is defined by sys/types.h instead of sys/sysmacros.h.
But once they fix it, we are good too. Or we can use the following
workaround in configure.ac:
+old_CFLAGS=$CFLAGS
+CFLAGS+=" -Werror "
AC_HEADER_MAJOR
+CFLAGS=$old_CFLAGS
src/conf/domain_audit.c | 3 ++-
src/lxc/lxc_controller.c | 2 +-
src/lxc/lxc_driver.c | 2 +-
src/util/vircgroup.c | 2 +-
src/util/virutil.c | 2 +-
5 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
index 53a58ac..52dea02 100644
--- a/src/conf/domain_audit.c
+++ b/src/conf/domain_audit.c
@@ -24,7 +24,6 @@
#include <config.h>
#include <sys/stat.h>
-#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
@@ -32,6 +31,8 @@
# include <sys/sysmacros.h>
#endif
+#include <sys/types.h>
+
#include "domain_audit.h"
#include "viraudit.h"
#include "viruuid.h"
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 825b4d4..8c581df 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -27,7 +27,6 @@
#include <sys/epoll.h>
#include <sys/wait.h>
#include <sys/socket.h>
-#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
@@ -35,6 +34,7 @@
# include <sys/sysmacros.h>
#endif
+#include <sys/types.h>
#include <sys/un.h>
#include <sys/personality.h>
#include <unistd.h>
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index da98b38..24025d1 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -28,7 +28,6 @@
#include <sched.h>
#include <sys/utsname.h>
#include <string.h>
-#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
@@ -36,6 +35,7 @@
# include <sys/sysmacros.h>
#endif
+#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index f2477d5..8b52816 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -34,7 +34,6 @@
#include <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
-#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
@@ -42,6 +41,7 @@
# include <sys/sysmacros.h>
#endif
+#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#include <unistd.h>
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 170dd59..b57a195 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -35,7 +35,6 @@
#include <errno.h>
#include <poll.h>
#include <sys/stat.h>
-#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
@@ -43,6 +42,7 @@
# include <sys/sysmacros.h>
#endif
+#include <sys/types.h>
#include <sys/ioctl.h>
#include <string.h>
#include <termios.h>
--
2.8.4
3
5
[libvirt] [PATCH 0/3] qemu: fix startup of NUMA pinned VM with hotpluggable vcpus
by Peter Krempa 13 Sep '16
by Peter Krempa 13 Sep '16
13 Sep '16
See patch 2 for explanation.
Peter Krempa (3):
qemu: cgroup: Extract temporary relaxing of cgroup setting for vcpu
hotplug
qemu: process: Fix start with unpluggable vcpus with NUMA pinning
qemu: driver: Remove unnecessary condition
src/qemu/qemu_cgroup.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_cgroup.h | 11 ++++++
src/qemu/qemu_driver.c | 38 +++------------------
src/qemu/qemu_process.c | 6 ++++
4 files changed, 112 insertions(+), 33 deletions(-)
--
2.10.0
3
5