[libvirt] [PATCH] qemu-migration: Disallow migration of read only disk
by Corey S. McQuay
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
8 years, 2 months
[libvirt] [PATCH 1/2] libxl: add support for PVH
by Marek Marczykowski-Górecki
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
8 years, 2 months
[libvirt] [PATCH 00/41] Enhance guest CPU configuration code
by Jiri Denemark
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
8 years, 2 months
[libvirt] [PATCH v1 0/4] libxl: host cpu element in capabilities
by Joao Martins
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
8 years, 2 months
[libvirt] [PATCH][RFC] enable modification of xml in case of a restore forthe combination of xen/libvirt
by Guido.Rossmueller@gdata.de
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
8 years, 2 months
[libvirt] [PATCH v2a] HyperV: Improve 2008, introduce 2012
by Jason Miesionczek
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
8 years, 2 months
[libvirt] [PATCH 00/16] Hyper-V: Improve 2008, Introduce 2012
by Jason Miesionczek
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
8 years, 2 months
[libvirt] [PATCH v2] qemu: map "virtio" video model to "virt" machtype correctly (arm/aarch64)
by Laszlo Ersek
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
8 years, 2 months
[libvirt] [PATCH] test driver: File test_driver.c was splitted into smaller files.
by Tomáš Ryšavý
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
8 years, 2 months