[libvirt] [v2] qemu: Introduce two new job types
by Osier Yang
Currently, all of domain "save/dump/managed save/migration"
use the same function "qemudDomainWaitForMigrationComplete"
to wait the job finished, but the error messages are all
about "migration", e.g. when a domain saving job is canceled
by user, "migration was cancled by client" will be throwed as
an error message, which will be confused for user.
As a solution, intoduce two new job types(QEMU_JOB_SAVE,
QEMU_JOB_DUMP), and set "priv->jobActive" to "QEMU_JOB_SAVE"
before saving, to "QEMU_JOB_DUMP" before dumping, so that we
could get the real job type in
"qemudDomainWaitForMigrationComplete", and give more clear
message further.
And as It's not important to figure out what's the exact job
is in the DEBUG and WARN log, also we don't need translated
string in logs, simply repace "migration" with "job" in some
statements.
* src/qemu/qemu_driver.c
---
src/qemu/qemu_driver.c | 40 +++++++++++++++++++++++++++++++---------
1 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 19ce9a6..d5af0df 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -104,6 +104,8 @@ enum qemuDomainJob {
QEMU_JOB_UNSPECIFIED,
QEMU_JOB_MIGRATION_OUT,
QEMU_JOB_MIGRATION_IN,
+ QEMU_JOB_SAVE,
+ QEMU_JOB_DUMP,
};
enum qemuDomainJobSignals {
@@ -5389,21 +5391,37 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
struct timeval now;
int rc;
+ const char *job;
+
+ switch (priv->jobActive) {
+ case QEMU_JOB_MIGRATION_OUT:
+ job = _("migration job");
+ break;
+ case QEMU_JOB_SAVE:
+ job = _("domain save job");
+ break;
+ case QEMU_JOB_DUMP:
+ job = _("domain core dump job");
+ break;
+ default:
+ job = _("job");
+ }
+
if (!virDomainObjIsActive(vm)) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("guest unexpectedly quit during migration"));
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s: %s",
+ job, _("guest unexpectedly quit"));
goto cleanup;
}
if (priv->jobSignals & QEMU_JOB_SIGNAL_CANCEL) {
priv->jobSignals ^= QEMU_JOB_SIGNAL_CANCEL;
- VIR_DEBUG0("Cancelling migration at client request");
+ VIR_DEBUG0("Cancelling job at client request");
qemuDomainObjEnterMonitorWithDriver(driver, vm);
rc = qemuMonitorMigrateCancel(priv->mon);
qemuDomainObjExitMonitorWithDriver(driver, vm);
if (rc < 0) {
- VIR_WARN0("Unable to cancel migration");
+ VIR_WARN0("Unable to cancel job");
}
} else if (priv->jobSignals & QEMU_JOB_SIGNAL_SUSPEND) {
priv->jobSignals ^= QEMU_JOB_SIGNAL_SUSPEND;
@@ -5427,8 +5445,8 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
* guest to die
*/
if (!virDomainObjIsActive(vm)) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("guest unexpectedly quit during migration"));
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s: %s",
+ job, _("guest unexpectedly quit"));
goto cleanup;
}
@@ -5459,7 +5477,7 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
priv->jobInfo.type = VIR_DOMAIN_JOB_NONE;
qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Migration is not active"));
+ "%s: %s", job, _("is not active"));
break;
case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
@@ -5480,13 +5498,13 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED;
qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Migration unexpectedly failed"));
+ "%s: %s", job, _("unexpectedly failed"));
break;
case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
priv->jobInfo.type = VIR_DOMAIN_JOB_CANCELLED;
qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Migration was cancelled by client"));
+ "%s: %s", job, _("canceled by client"));
break;
}
@@ -5606,6 +5624,8 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
goto endjob;
}
+ priv->jobActive = QEMU_JOB_SAVE;
+
memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
@@ -6198,6 +6218,8 @@ static int qemudDomainCoreDump(virDomainPtr dom,
goto endjob;
}
+ priv->jobActive = QEMU_JOB_DUMP;
+
/* Migrate will always stop the VM, so the resume condition is
independent of whether the stop command is issued. */
resume = (vm->state == VIR_DOMAIN_RUNNING);
--
1.7.3.2
14 years
[libvirt] [PATCH] daemon: plug a memory leak
by Eric Blake
* daemon/libvirtd.c (qemudFreeClient): Avoid a leak.
(qemudDispatchServer): Avoid null dereference.
---
I keep finding more of these.
daemon/libvirtd.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 791b3dc..2914f2f 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1410,7 +1410,7 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket
/* Client is running as root, so disable auth */
if (uid == 0) {
VIR_INFO(_("Turn off polkit auth for privileged client pid %d from %s"),
- pid, addrstr);
+ pid, client->addrstr);
client->auth = REMOTE_AUTH_NONE;
}
}
@@ -1451,7 +1451,7 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket
} else {
PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
VIR_ERROR(_("TLS handshake failed for client %s: %s"),
- addrstr, gnutls_strerror (ret));
+ client->addrstr, gnutls_strerror (ret));
goto error;
}
}
@@ -2283,6 +2283,7 @@ static void qemudFreeClient(struct qemud_client *client) {
if (client->conn)
virConnectClose(client->conn);
virMutexDestroy(&client->lock);
+ VIR_FREE(client->addrstr);
VIR_FREE(client);
}
--
1.7.3.2
14 years
[libvirt] [PATCH] qemu: Introduce two new job types
by Osier Yang
Currently, all of domain "save/dump/managed save/migration"
use the same function "qemudDomainWaitForMigrationComplete"
to wait the job finished, but the error messages are all
about "migration", e.g. when a domain saving job is canceled
by user, "migration was cancled by client" will be throwed as
an error message, which will be confused for user.
As a solution, intoduce two new job types(QEMU_JOB_SAVE,
QEMU_JOB_DUMP), and set "priv->jobActive" to "QEMU_JOB_SAVE"
before saving, to "QEMU_JOB_DUMP" before dumping, so that we
could get the real job type in
"qemudDomainWaitForMigrationComplete", and give more clear
message further.
* src/qemu/qemu_driver.c
---
src/qemu/qemu_driver.c | 39 ++++++++++++++++++++++++++++++---------
1 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 19ce9a6..aed48f4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -104,6 +104,8 @@ enum qemuDomainJob {
QEMU_JOB_UNSPECIFIED,
QEMU_JOB_MIGRATION_OUT,
QEMU_JOB_MIGRATION_IN,
+ QEMU_JOB_SAVE,
+ QEMU_JOB_DUMP,
};
enum qemuDomainJobSignals {
@@ -5389,21 +5391,36 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
struct timeval now;
int rc;
+ const char *job;
+
+ switch (priv->jobActive) {
+ case QEMU_JOB_MIGRATION_OUT:
+ job = "migration";
+ break;
+ case QEMU_JOB_SAVE:
+ job = "domain saving";
+ break;
+ case QEMU_JOB_DUMP:
+ job = "domain core dump";
+ break;
+ default:
+ job = "job";
+ }
if (!virDomainObjIsActive(vm)) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("guest unexpectedly quit during migration"));
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("guest unexpectedly quit during %s"), job);
goto cleanup;
}
if (priv->jobSignals & QEMU_JOB_SIGNAL_CANCEL) {
priv->jobSignals ^= QEMU_JOB_SIGNAL_CANCEL;
- VIR_DEBUG0("Cancelling migration at client request");
+ VIR_DEBUG("Cancelling %s at client request", job);
qemuDomainObjEnterMonitorWithDriver(driver, vm);
rc = qemuMonitorMigrateCancel(priv->mon);
qemuDomainObjExitMonitorWithDriver(driver, vm);
if (rc < 0) {
- VIR_WARN0("Unable to cancel migration");
+ VIR_WARN("Unable to cancel %s", job);
}
} else if (priv->jobSignals & QEMU_JOB_SIGNAL_SUSPEND) {
priv->jobSignals ^= QEMU_JOB_SIGNAL_SUSPEND;
@@ -5427,8 +5444,8 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
* guest to die
*/
if (!virDomainObjIsActive(vm)) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("guest unexpectedly quit during migration"));
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("guest unexpectedly quit during %s"), job);
goto cleanup;
}
@@ -5459,7 +5476,7 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
priv->jobInfo.type = VIR_DOMAIN_JOB_NONE;
qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Migration is not active"));
+ _("%s is not active"), job);
break;
case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
@@ -5480,13 +5497,13 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED;
qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Migration unexpectedly failed"));
+ _("%s unexpectedly failed"), job);
break;
case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
priv->jobInfo.type = VIR_DOMAIN_JOB_CANCELLED;
qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("Migration was cancelled by client"));
+ _("%s was cancelled by client"), job);
break;
}
@@ -5606,6 +5623,8 @@ static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
goto endjob;
}
+ priv->jobActive = QEMU_JOB_SAVE;
+
memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
@@ -6198,6 +6217,8 @@ static int qemudDomainCoreDump(virDomainPtr dom,
goto endjob;
}
+ priv->jobActive = QEMU_JOB_DUMP;
+
/* Migrate will always stop the VM, so the resume condition is
independent of whether the stop command is issued. */
resume = (vm->state == VIR_DOMAIN_RUNNING);
--
1.7.3.2
14 years
[libvirt] ANNOUNCE: ruby-libvirt bindings 0.3.0
by Chris Lalancette
All,
I'm pleased to announce the release of 0.3.0 of the ruby-libvirt bindings.
This release has a number of updates:
* Implementation of Libvirt::open_auth, Libvirt::event_register_impl
* Updated Connect class, implementing conn.compare_cpu, conn.baseline_cpu,
conn.domain_event_register_any, conn.domain_event_deregister_any,
conn.domain_event_register, conn.domain_event_deregister, and
conn.create_domain_xml.
* Updated Domain class, implementing dom.get_vcpus, dom.update_device,
dom.scheduler_type, dom.scheduler_parameters, dom.scheduler_parameters=,
dom.num_vcpus, dom.vcpus_flags=, and dom.qemu_monitor_command.
* Updated Interface class, implementing interface.free
* Many potential memory leaks have been fixed.
* Many bugfixes.
* Documentation update of many methods, including all of the lookup methods
that were missing before.
With the above list, almost all of the APIs up to and including libvirt 0.8.6
are covered. There are a few that I have not yet had time to implement; you
can look at the list in the README file in the source tree to see which ones
are missing.
The tarballs and source RPMs are here: http://libvirt.org/ruby/download/
The git repository is here: http://libvirt.org/git/?p=ruby-libvirt.git;a=summary
The documentation for all of the APIs are here: http://libvirt.org/ruby/api/index.html
I've uploaded some examples on how to use the bindings:
http://libvirt.org/ruby/documentation.html
I've also pushed a new gem to rubygems.org; you should be able to use
'gem install ruby-libvirt' (if you haven't installed them before) or
'gem update ruby-libvirt' (if you have them installed already).
If you have time, and are interested in the bindings, please give these new
ones a whirl and let me know if they work for you. Note that release 0.3.0
is intended to be fully backwards compatible with release 0.2.0 and 0.1.0.
If you find that they are not, or find any other problems with the ruby
bindings, please report it to the libvirt development mailing list
(and CC me) so that I can take a look at them.
Thanks,
--
Chris Lalancette
14 years
[libvirt] [PATCH] Convert dhcpStartDhcpDaemon from virRun to virCommand
by Laine Stump
This is pretty straightforward - even though dnsmasq gets daemonized
and uses a pid file, those things are both handled by the dnsmasq
binary itself. And libvirt doesn't need any of the output of the
dnsmasq command either, so we just setup the args and call
virRun(). Mainly it was just a (mostly) mechanical job of replacing
the APPEND_ARG() macro (and some other *printfs()) with
virCommandAddArg*().
---
src/network/bridge_driver.c | 238 +++++++++++++++----------------------------
1 files changed, 80 insertions(+), 158 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 62639e4..9802222 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -51,6 +51,7 @@
#include "event.h"
#include "buf.h"
#include "util.h"
+#include "command.h"
#include "memory.h"
#include "uuid.h"
#include "iptables.h"
@@ -390,25 +391,15 @@ networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
static int
networkBuildDnsmasqArgv(virNetworkObjPtr network,
const char *pidfile,
- const char ***argv) {
- int i, len, r;
+ virCommandPtr cmd) {
+ int r, ret = -1;
int nbleases = 0;
- char *pidfileArg;
- char buf[1024];
- unsigned int ranges;
- char *ipAddr;
-
- /*
- * For static-only DHCP, i.e. with no range but at least one host element,
- * we have to add a special --dhcp-range option to enable the service in
- * dnsmasq.
- */
- ranges = network->def->nranges;
- if (!ranges && network->def->nhosts)
- ranges = 1;
+ char *bridgeaddr;
+ if (!(bridgeaddr = virSocketFormatAddr(&network->def->ipAddress)))
+ goto cleanup;
/*
- * NB, be careful about syntax for dnsmasq options in long format
+ * NB, be careful about syntax for dnsmasq options in long format.
*
* If the flag has a mandatory argument, it can be given using
* either syntax:
@@ -422,66 +413,27 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
* --foo=bar
*
* It is hard to determine whether a flag is optional or not,
- * without reading the dnsmasq source :-( The manpages is not
- * very explicit on this
+ * without reading the dnsmasq source :-( The manpage is not
+ * very explicit on this.
*/
- len =
- 1 + /* dnsmasq */
- 1 + /* --strict-order */
- 1 + /* --bind-interfaces */
- (network->def->domain?2:0) + /* --domain name */
- 2 + /* --pid-file /var/run/libvirt/network/$NAME.pid */
- 2 + /* --conf-file "" */
- /*2 + *//* --interface virbr0 */
- 2 + /* --except-interface lo */
- 2 + /* --listen-address 10.0.0.1 */
- (2 * ranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
- /* --dhcp-lease-max=xxx if needed */
- (network->def->nranges ? 1 : 0) +
- /* --dhcp-no-override if needed */
- (ranges ? 1 : 0) +
- /* --dhcp-hostsfile=/var/lib/dnsmasq/$NAME.hostsfile */
- (network->def->nhosts > 0 ? 1 : 0) +
- /* --enable-tftp --tftp-root /srv/tftp */
- (network->def->tftproot ? 3 : 0) +
- /* --dhcp-boot pxeboot.img[,,12.34.56.78] */
- (network->def->bootfile ? 2 : 0) +
- 1; /* NULL */
-
- if (VIR_ALLOC_N(*argv, len) < 0)
- goto no_memory;
-
-#define APPEND_ARG(v, n, s) do { \
- if (!((v)[(n)] = strdup(s))) \
- goto no_memory; \
- } while (0)
-
-#define APPEND_ARG_LIT(v, n, s) \
- (v)[(n)] = s
-
- i = 0;
-
- APPEND_ARG(*argv, i++, DNSMASQ);
-
/*
* Needed to ensure dnsmasq uses same algorithm for processing
* multiple namedriver entries in /etc/resolv.conf as GLibC.
*/
- APPEND_ARG(*argv, i++, "--strict-order");
- APPEND_ARG(*argv, i++, "--bind-interfaces");
+ virCommandAddArg(cmd, "--strict-order");
+ virCommandAddArg(cmd, "--bind-interfaces");
if (network->def->domain) {
- APPEND_ARG(*argv, i++, "--domain");
- APPEND_ARG(*argv, i++, network->def->domain);
+ virCommandAddArg(cmd, "--domain");
+ virCommandAddArg(cmd, network->def->domain);
}
- if (virAsprintf(&pidfileArg, "--pid-file=%s", pidfile) < 0)
- goto no_memory;
- APPEND_ARG_LIT(*argv, i++, pidfileArg);
+ virCommandAddArgPair(cmd, "--pid-file", pidfile);
- APPEND_ARG(*argv, i++, "--conf-file=");
- APPEND_ARG(*argv, i++, "");
+ /* *no* conf file */
+ virCommandAddArg(cmd, "--conf-file=");
+ virCommandAddArg(cmd, "");
/*
* XXX does not actually work, due to some kind of
@@ -489,166 +441,140 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
* interface. A sleep(10) makes it work, but that's
* clearly not practical
*
- * APPEND_ARG(*argv, i++, "--interface");
- * APPEND_ARG(*argv, i++, network->def->bridge);
+ * virCommandAddArg(cmd, "--interface");
+ * virCommandAddArg(cmd, network->def->bridge);
*/
- APPEND_ARG(*argv, i++, "--listen-address");
- if (!(ipAddr = virSocketFormatAddr(&network->def->ipAddress)))
- goto error;
- APPEND_ARG_LIT(*argv, i++, ipAddr);
+ virCommandAddArg(cmd, "--listen-address");
+ virCommandAddArg(cmd, bridgeaddr);
- APPEND_ARG(*argv, i++, "--except-interface");
- APPEND_ARG(*argv, i++, "lo");
+ virCommandAddArg(cmd, "--except-interface");
+ virCommandAddArg(cmd, "lo");
for (r = 0 ; r < network->def->nranges ; r++) {
char *saddr = virSocketFormatAddr(&network->def->ranges[r].start);
if (!saddr)
- goto error;
+ goto cleanup;
char *eaddr = virSocketFormatAddr(&network->def->ranges[r].end);
if (!eaddr) {
VIR_FREE(saddr);
- goto error;
+ goto cleanup;
}
- char *range;
- int rc = virAsprintf(&range, "%s,%s", saddr, eaddr);
+ virCommandAddArg(cmd, "--dhcp-range");
+ virCommandAddArgFormat(cmd, "%s,%s", saddr, eaddr);
VIR_FREE(saddr);
VIR_FREE(eaddr);
- if (rc < 0)
- goto no_memory;
- APPEND_ARG(*argv, i++, "--dhcp-range");
- APPEND_ARG_LIT(*argv, i++, range);
nbleases += virSocketGetRange(&network->def->ranges[r].start,
&network->def->ranges[r].end);
}
+ /*
+ * For static-only DHCP, i.e. with no range but at least one host element,
+ * we have to add a special --dhcp-range option to enable the service in
+ * dnsmasq.
+ */
if (!network->def->nranges && network->def->nhosts) {
- char *ipaddr = virSocketFormatAddr(&network->def->ipAddress);
- if (!ipaddr)
- goto error;
- char *range;
- int rc = virAsprintf(&range, "%s,static", ipaddr);
- VIR_FREE(ipaddr);
- if (rc < 0)
- goto no_memory;
-
- APPEND_ARG(*argv, i++, "--dhcp-range");
- APPEND_ARG_LIT(*argv, i++, range);
+ virCommandAddArg(cmd, "--dhcp-range");
+ virCommandAddArgFormat(cmd, "%s,static", bridgeaddr);
}
if (network->def->nranges > 0) {
- snprintf(buf, sizeof(buf), "--dhcp-lease-max=%d", nbleases);
- APPEND_ARG(*argv, i++, buf);
+ virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases);
}
- if (ranges)
- APPEND_ARG(*argv, i++, "--dhcp-no-override");
+ if (network->def->nranges || network->def->nhosts)
+ virCommandAddArg(cmd, "--dhcp-no-override");
if (network->def->nhosts > 0) {
- dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
- char *hostsfileArg;
-
- if (dctx == NULL)
- goto no_memory;
+ dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
+ DNSMASQ_STATE_DIR);
+ if (dctx == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
if (networkSaveDnsmasqHostsfile(network, dctx, false)) {
- if (virAsprintf(&hostsfileArg, "--dhcp-hostsfile=%s", dctx->hostsfile->path) < 0) {
- dnsmasqContextFree(dctx);
- goto no_memory;
- }
- APPEND_ARG_LIT(*argv, i++, hostsfileArg);
+ virCommandAddArgPair(cmd, "--dhcp-hostsfile",
+ dctx->hostsfile->path);
}
-
dnsmasqContextFree(dctx);
}
if (network->def->tftproot) {
- APPEND_ARG(*argv, i++, "--enable-tftp");
- APPEND_ARG(*argv, i++, "--tftp-root");
- APPEND_ARG(*argv, i++, network->def->tftproot);
+ virCommandAddArg(cmd, "--enable-tftp");
+ virCommandAddArg(cmd, "--tftp-root");
+ virCommandAddArg(cmd, network->def->tftproot);
}
if (network->def->bootfile) {
- char *ipaddr = NULL;
+
+ virCommandAddArg(cmd, "--dhcp-boot");
if (VIR_SOCKET_HAS_ADDR(&network->def->bootserver)) {
- if (!(ipaddr = virSocketFormatAddr(&network->def->bootserver)))
- goto error;
- }
- char *boot;
- int rc = virAsprintf(&boot, "%s%s%s",
- network->def->bootfile,
- ipaddr ? ",," : "",
- ipaddr ? ipaddr : "");
- VIR_FREE(ipaddr);
- if (rc < 0)
- goto no_memory;
+ char *bootserver = virSocketFormatAddr(&network->def->bootserver);
- APPEND_ARG(*argv, i++, "--dhcp-boot");
- APPEND_ARG_LIT(*argv, i++, boot);
+ if (!bootserver)
+ goto cleanup;
+ virCommandAddArgFormat(cmd, "%s%s%s",
+ network->def->bootfile, ",,", bootserver);
+ VIR_FREE(bootserver);
+ } else {
+ virCommandAddArg(cmd, network->def->bootfile);
+ }
}
-#undef APPEND_ARG
-
- return 0;
-
- no_memory:
- virReportOOMError();
- error:
- if (*argv) {
- for (i = 0; (*argv)[i]; i++)
- VIR_FREE((*argv)[i]);
- VIR_FREE(*argv);
- }
- return -1;
+ ret = 0;
+cleanup:
+ VIR_FREE(bridgeaddr);
+ return ret;
}
static int
dhcpStartDhcpDaemon(virNetworkObjPtr network)
{
- const char **argv;
- char *pidfile;
- int ret = -1, i, err;
+ virCommandPtr cmd = NULL;
+ char *pidfile = NULL;
+ int ret = -1, err;
network->dnsmasqPid = -1;
if (!VIR_SOCKET_IS_FAMILY(&network->def->ipAddress, AF_INET)) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot start dhcp daemon without IPv4 address for server"));
- return -1;
+ goto cleanup;
}
if ((err = virFileMakePath(NETWORK_PID_DIR)) != 0) {
virReportSystemError(err,
_("cannot create directory %s"),
NETWORK_PID_DIR);
- return -1;
+ goto cleanup;
}
if ((err = virFileMakePath(NETWORK_STATE_DIR)) != 0) {
virReportSystemError(err,
_("cannot create directory %s"),
NETWORK_STATE_DIR);
- return -1;
+ goto cleanup;
}
if (!(pidfile = virFilePid(NETWORK_PID_DIR, network->def->name))) {
virReportOOMError();
- return -1;
+ goto cleanup;
}
- argv = NULL;
- if (networkBuildDnsmasqArgv(network, pidfile, &argv) < 0) {
+ cmd = virCommandNew(DNSMASQ);
+ if (networkBuildDnsmasqArgv(network, pidfile, cmd) < 0) {
VIR_FREE(pidfile);
- return -1;
+ goto cleanup;
}
- if (virRun(argv, NULL) < 0)
+ if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
/*
- * There really is no race here - when dnsmasq daemonizes,
- * its leader process stays around until its child has
- * actually written its pidfile. So by time virRun exits
- * it has waitpid'd and guaranteed the proess has started
- * and written a pid
+ * There really is no race here - when dnsmasq daemonizes, its
+ * leader process stays around until its child has actually
+ * written its pidfile. So by time virCommandRun exits it has
+ * waitpid'd and guaranteed the proess has started and written a
+ * pid
*/
if (virFileReadPid(NETWORK_PID_DIR, network->def->name,
@@ -656,13 +582,9 @@ dhcpStartDhcpDaemon(virNetworkObjPtr network)
goto cleanup;
ret = 0;
-
cleanup:
VIR_FREE(pidfile);
- for (i = 0; argv[i]; i++)
- VIR_FREE(argv[i]);
- VIR_FREE(argv);
-
+ virCommandFree(cmd);
return ret;
}
--
1.7.3.2
14 years
[libvirt] [PATCH 0/4] more memory leak patches
by Eric Blake
More in the ongoing battle to make libvirtd not so leaky.
Also related, and still waiting on a review for:
virExec (and thus virCommand) have undefined behavior
https://www.redhat.com/archives/libvir-list/2010-December/msg00242.html
avoid matchpathcon memory leak (although libselinux 2.0.97 finally
patched that leak upstream)
https://www.redhat.com/archives/libvir-list/2010-December/msg00001.html
The leak in qemu_conf covered in patch 3 was introduced with the
conversion to virCommand; if you like patch 4, I'd rather combine
those into one patch (but patch 3 is a minimal plug).
Eric Blake (4):
tests: plug memory leaks
conf: plug memory leaks
qemu: plug memory leak
command: ease use with virBuffer
src/conf/domain_conf.c | 10 ++++++++++
src/libvirt_private.syms | 2 ++
src/qemu/qemu_conf.c | 42 +++++++++---------------------------------
src/util/command.c | 43 +++++++++++++++++++++++++++++++++++++++++++
src/util/command.h | 17 +++++++++++++++++
tests/qemuxml2argvtest.c | 3 +--
6 files changed, 82 insertions(+), 35 deletions(-)
--
1.7.3.2
14 years
[libvirt] [PATCH] virExec: avoid undefined behavior
by Eric Blake
* src/util/util.c (__virExec): Don't use FD_ISSET on out-of-bounds fd.
---
Noticed this one by inspection, while investigating
https://bugzilla.redhat.com/show_bug.cgi?id=659855
Don't know if it's the root cause of the crash in that bug, though.
src/util/util.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index 79ca5d3..1b5bc68 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -570,8 +570,7 @@ __virExec(const char *const*argv,
i != null &&
i != childout &&
i != childerr &&
- (!keepfd ||
- !FD_ISSET(i, keepfd))) {
+ (!keepfd || (i < FD_SETSIZE && !FD_ISSET(i, keepfd)))) {
tmpfd = i;
VIR_FORCE_CLOSE(tmpfd);
}
--
1.7.3.2
14 years
[libvirt] [PATCH] esx: Refactor storage pool type lookup into a function
by Matthias Bolte
---
src/esx/esx_storage_driver.c | 130 ++++++++++++++++++------------------------
1 files changed, 56 insertions(+), 74 deletions(-)
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 83b53fb..9165f7a 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -49,6 +49,58 @@ verify(MD5_DIGEST_SIZE == VIR_UUID_BUFLEN);
+static int
+esxStoragePoolLookupType(esxVI_Context *ctx, const char *poolName,
+ int *poolType)
+{
+ int result = -1;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_DatastoreInfo *datastoreInfo = NULL;
+
+ if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
+ esxVI_LookupDatastoreByName(ctx, poolName, propertyNameList, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "info")) {
+ if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+ &datastoreInfo) < 0) {
+ goto cleanup;
+ }
+
+ break;
+ }
+ }
+
+ if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+ *poolType = VIR_STORAGE_POOL_DIR;
+ } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+ *poolType = VIR_STORAGE_POOL_NETFS;
+ } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
+ *poolType = VIR_STORAGE_POOL_FS;
+ } else {
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("DatastoreInfo has unexpected type"));
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+ esxVI_DatastoreInfo_Free(&datastoreInfo);
+
+ return result;
+}
+
+
+
static virDrvOpenStatus
esxStorageOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
@@ -908,10 +960,6 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
{
virStorageVolPtr volume = NULL;
esxPrivate *priv = pool->conn->storagePrivateData;
- esxVI_String *propertyNameList = NULL;
- esxVI_ObjectContent *datastore = NULL;
- esxVI_DynamicProperty *dynamicProperty = NULL;
- esxVI_DatastoreInfo *datastoreInfo = NULL;
virStoragePoolDef poolDef;
virStorageVolDefPtr def = NULL;
char *tmp;
@@ -938,36 +986,8 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
return NULL;
}
- /* Lookup storage pool type */
- if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
- esxVI_LookupDatastoreByName(priv->primary, pool->name,
- propertyNameList, &datastore,
- esxVI_Occurrence_RequiredItem) < 0) {
- goto cleanup;
- }
-
- for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
- dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "info")) {
- if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
- &datastoreInfo) < 0) {
- goto cleanup;
- }
-
- break;
- }
- }
-
- if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- poolDef.type = VIR_STORAGE_POOL_DIR;
- } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- poolDef.type = VIR_STORAGE_POOL_NETFS;
- } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- poolDef.type = VIR_STORAGE_POOL_FS;
- } else {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
- _("DatastoreInfo has unexpected type"));
- goto cleanup;
+ if (esxStoragePoolLookupType(priv->primary, pool->name, &poolDef.type) < 0) {
+ return NULL;
}
/* Parse config */
@@ -1140,9 +1160,6 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
virtualDiskSpec->adapterType = NULL;
}
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
- esxVI_DatastoreInfo_Free(&datastoreInfo);
virStorageVolDefFree(def);
VIR_FREE(unescapedDatastorePath);
VIR_FREE(unescapedDirectoryName);
@@ -1216,10 +1233,6 @@ static char *
esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags)
{
esxPrivate *priv = volume->conn->storagePrivateData;
- esxVI_String *propertyNameList = NULL;
- esxVI_ObjectContent *datastore = NULL;
- esxVI_DynamicProperty *dynamicProperty = NULL;
- esxVI_DatastoreInfo *datastoreInfo = NULL;
virStoragePoolDef pool;
char *datastorePath = NULL;
esxVI_FileInfo *fileInfo = NULL;
@@ -1238,36 +1251,8 @@ esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags)
return NULL;
}
- /* Lookup storage pool type */
- if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
- esxVI_LookupDatastoreByName(priv->primary, volume->pool,
- propertyNameList, &datastore,
- esxVI_Occurrence_RequiredItem) < 0) {
- goto cleanup;
- }
-
- for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
- dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "info")) {
- if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
- &datastoreInfo) < 0) {
- goto cleanup;
- }
-
- break;
- }
- }
-
- if (esxVI_LocalDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- pool.type = VIR_STORAGE_POOL_DIR;
- } else if (esxVI_NasDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- pool.type = VIR_STORAGE_POOL_NETFS;
- } else if (esxVI_VmfsDatastoreInfo_DynamicCast(datastoreInfo) != NULL) {
- pool.type = VIR_STORAGE_POOL_FS;
- } else {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
- _("DatastoreInfo has unexpected type"));
- goto cleanup;
+ if (esxStoragePoolLookupType(priv->primary, volume->pool, &pool.type) < 0) {
+ return NULL;
}
/* Lookup file info */
@@ -1320,9 +1305,6 @@ esxStorageVolumeDumpXML(virStorageVolPtr volume, unsigned int flags)
xml = virStorageVolDefFormat(&pool, &def);
cleanup:
- esxVI_String_Free(&propertyNameList);
- esxVI_ObjectContent_Free(&datastore);
- esxVI_DatastoreInfo_Free(&datastoreInfo);
VIR_FREE(datastorePath);
esxVI_FileInfo_Free(&fileInfo);
VIR_FREE(def.key);
--
1.7.0.4
14 years
[libvirt] [PATCH] esx: Improve error reporting for failed tasks
by Matthias Bolte
Instead of just reporting that a task failed get the
localized message from the TaskInfo error and include
it in the reported error message.
Implement minimal deserialization support for the
MethodFault type in order to obtain the actual fault
type.
For example, this changes the reported error message
when trying to create a volume with zero size from
Could not create volume
to
Could not create volume: InvalidArgument - A specified parameter was not correct.
Not perfect yet, but better than before.
---
src/esx/esx_driver.c | 118 +++++++++++++++++++++++++++++-----------
src/esx/esx_storage_driver.c | 8 ++-
src/esx/esx_vi.c | 53 ++++++++++++++++--
src/esx/esx_vi.h | 3 +-
src/esx/esx_vi_generator.input | 8 +++-
src/esx/esx_vi_generator.py | 2 +
src/esx/esx_vi_types.c | 51 +++++++++++++++++-
src/esx/esx_vi_types.h | 25 +++++++++
8 files changed, 227 insertions(+), 41 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 8ea6219..03a7be3 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -1706,6 +1706,7 @@ esxDomainSuspend(virDomainPtr domain)
esxVI_VirtualMachinePowerState powerState;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
@@ -1729,12 +1730,14 @@ esxDomainSuspend(virDomainPtr domain)
if (esxVI_SuspendVM_Task(priv->primary, virtualMachine->obj, &task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not suspend domain"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not suspend domain: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -1744,6 +1747,7 @@ esxDomainSuspend(virDomainPtr domain)
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_String_Free(&propertyNameList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -1760,6 +1764,7 @@ esxDomainResume(virDomainPtr domain)
esxVI_VirtualMachinePowerState powerState;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
@@ -1783,12 +1788,14 @@ esxDomainResume(virDomainPtr domain)
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not resume domain"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not resume domain: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -1798,6 +1805,7 @@ esxDomainResume(virDomainPtr domain)
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_String_Free(&propertyNameList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -1901,6 +1909,7 @@ esxDomainDestroy(virDomainPtr domain)
esxVI_VirtualMachinePowerState powerState;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (priv->vCenter != NULL) {
ctx = priv->vCenter;
@@ -1930,12 +1939,14 @@ esxDomainDestroy(virDomainPtr domain)
if (esxVI_PowerOffVM_Task(ctx, virtualMachine->obj, &task) < 0 ||
esxVI_WaitForTaskCompletion(ctx, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not destroy domain"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not destroy domain: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -1946,6 +1957,7 @@ esxDomainDestroy(virDomainPtr domain)
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_String_Free(&propertyNameList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -2028,6 +2040,7 @@ esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
esxVI_VirtualMachineConfigSpec *spec = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
@@ -2048,13 +2061,15 @@ esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not set max-memory to %lu kilobytes"), memory);
+ _("Could not set max-memory to %lu kilobytes: %s"), memory,
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -2064,6 +2079,7 @@ esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_VirtualMachineConfigSpec_Free(&spec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -2079,6 +2095,7 @@ esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
esxVI_VirtualMachineConfigSpec *spec = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
return -1;
@@ -2100,13 +2117,15 @@ esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not set memory to %lu kilobytes"), memory);
+ _("Could not set memory to %lu kilobytes: %s"), memory,
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -2116,6 +2135,7 @@ esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_VirtualMachineConfigSpec_Free(&spec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -2394,6 +2414,7 @@ esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
esxVI_VirtualMachineConfigSpec *spec = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (flags != VIR_DOMAIN_VCPU_LIVE) {
ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
@@ -2438,13 +2459,15 @@ esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not set number of virtual CPUs to %d"), nvcpus);
+ _("Could not set number of virtual CPUs to %d: %s"), nvcpus,
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -2454,6 +2477,7 @@ esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_VirtualMachineConfigSpec_Free(&spec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -2828,6 +2852,7 @@ esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
int id = -1;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
virCheckFlags(0, -1);
@@ -2855,12 +2880,14 @@ esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not start domain"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not start domain: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -2871,6 +2898,7 @@ esxDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_String_Free(&propertyNameList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -2907,6 +2935,7 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
esxVI_ManagedObjectReference *resourcePool = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
virDomainPtr domain = NULL;
if (esxVI_EnsureSession(priv->primary) < 0) {
@@ -3066,12 +3095,14 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, def->uuid,
esxVI_Occurrence_OptionalItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not define domain"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not define domain: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -3100,6 +3131,7 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
esxVI_ObjectContent_Free(&hostSystem);
esxVI_ManagedObjectReference_Free(&resourcePool);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return domain;
}
@@ -3340,6 +3372,7 @@ esxDomainSetSchedulerParameters(virDomainPtr domain,
esxVI_SharesInfo *sharesInfo = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
int i;
if (esxVI_EnsureSession(priv->primary) < 0) {
@@ -3434,13 +3467,15 @@ esxDomainSetSchedulerParameters(virDomainPtr domain,
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Could not change scheduler parameters"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Could not change scheduler parameters: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -3450,6 +3485,7 @@ esxDomainSetSchedulerParameters(virDomainPtr domain,
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_VirtualMachineConfigSpec_Free(&spec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -3504,6 +3540,7 @@ esxDomainMigratePerform(virDomainPtr domain,
esxVI_Event *eventList = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
if (priv->vCenter == NULL) {
ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
@@ -3601,14 +3638,16 @@ esxDomainMigratePerform(virDomainPtr domain,
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->vCenter, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Could not migrate domain, migration task finished with "
- "an error"));
+ "an error: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -3619,6 +3658,7 @@ esxDomainMigratePerform(virDomainPtr domain,
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_Event_Free(&eventList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -3783,6 +3823,7 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
virDomainSnapshotPtr snapshot = NULL;
virCheckFlags(0, NULL);
@@ -3820,12 +3861,14 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
esxVI_Boolean_False, &task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create snapshot"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not create snapshot: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -3836,6 +3879,7 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return snapshot;
}
@@ -4058,6 +4102,7 @@ esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
esxVI_VirtualMachineSnapshotTree *snapshotTreeParent = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
virCheckFlags(0, -1);
@@ -4077,13 +4122,15 @@ esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not revert to snapshot '%s'"), snapshot->name);
+ _("Could not revert to snapshot '%s': %s"), snapshot->name,
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -4092,6 +4139,7 @@ esxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
cleanup:
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -4109,6 +4157,7 @@ esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
esxVI_Boolean removeChildren = esxVI_Boolean_False;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);
@@ -4132,13 +4181,15 @@ esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
removeChildren, &task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, snapshot->domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not delete snapshot '%s'"), snapshot->name);
+ _("Could not delete snapshot '%s': %s"), snapshot->name,
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -4147,6 +4198,7 @@ esxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
cleanup:
esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotList);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
@@ -4163,6 +4215,7 @@ esxDomainSetMemoryParameters(virDomainPtr domain, virMemoryParameterPtr params,
esxVI_VirtualMachineConfigSpec *spec = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
int i;
virCheckFlags(0, -1);
@@ -4199,13 +4252,15 @@ esxDomainSetMemoryParameters(virDomainPtr domain, virMemoryParameterPtr params,
&task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Could not change memory parameters"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Could not change memory parameters: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -4215,6 +4270,7 @@ esxDomainSetMemoryParameters(virDomainPtr domain, virMemoryParameterPtr params,
esxVI_ObjectContent_Free(&virtualMachine);
esxVI_VirtualMachineConfigSpec_Free(&spec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
return result;
}
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 72e0d7a..83b53fb 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -926,6 +926,7 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
char *uuid_string = NULL;
char *key = NULL;
@@ -1092,12 +1093,14 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
esxVI_Occurrence_None,
- priv->autoAnswer, &taskInfoState) < 0) {
+ priv->autoAnswer, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
- ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create volume"));
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, _("Could not create volume: %s"),
+ taskInfoErrorMessage);
goto cleanup;
}
@@ -1151,6 +1154,7 @@ esxStorageVolumeCreateXML(virStoragePoolPtr pool, const char *xmldesc,
esxVI_FileInfo_Free(&fileInfo);
esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
VIR_FREE(uuid_string);
VIR_FREE(key);
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 9c96650..74a2a42 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -3009,6 +3009,7 @@ esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
esxVI_FloppyImageFileQuery *floppyImageFileQuery = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
esxVI_TaskInfo *taskInfo = NULL;
esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
@@ -3128,13 +3129,15 @@ esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
datastorePathWithoutFileName, searchSpec,
&task) < 0 ||
esxVI_WaitForTaskCompletion(ctx, task, NULL, esxVI_Occurrence_None,
- esxVI_Boolean_False, &taskInfoState) < 0) {
+ esxVI_Boolean_False, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not serach in datastore '%s'"), datastoreName);
+ _("Could not search in datastore '%s': %s"),
+ datastoreName, taskInfoErrorMessage);
goto cleanup;
}
@@ -3179,6 +3182,7 @@ esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
esxVI_ManagedObjectReference_Free(&hostDatastoreBrowser);
esxVI_HostDatastoreBrowserSearchSpec_Free(&searchSpec);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
esxVI_TaskInfo_Free(&taskInfo);
esxVI_HostDatastoreBrowserSearchResults_Free(&searchResults);
@@ -3203,6 +3207,7 @@ esxVI_LookupDatastoreContentByDatastoreName
char *datastorePath = NULL;
esxVI_ManagedObjectReference *task = NULL;
esxVI_TaskInfoState taskInfoState;
+ char *taskInfoErrorMessage = NULL;
esxVI_TaskInfo *taskInfo = NULL;
if (searchResultsList == NULL || *searchResultsList != NULL) {
@@ -3269,13 +3274,15 @@ esxVI_LookupDatastoreContentByDatastoreName
datastorePath, searchSpec,
&task) < 0 ||
esxVI_WaitForTaskCompletion(ctx, task, NULL, esxVI_Occurrence_None,
- esxVI_Boolean_False, &taskInfoState) < 0) {
+ esxVI_Boolean_False, &taskInfoState,
+ &taskInfoErrorMessage) < 0) {
goto cleanup;
}
if (taskInfoState != esxVI_TaskInfoState_Success) {
ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
- _("Could not serach in datastore '%s'"), datastoreName);
+ _("Could not serach in datastore '%s': %s"),
+ datastoreName, taskInfoErrorMessage);
goto cleanup;
}
@@ -3294,6 +3301,7 @@ esxVI_LookupDatastoreContentByDatastoreName
esxVI_HostDatastoreBrowserSearchSpec_Free(&searchSpec);
VIR_FREE(datastorePath);
esxVI_ManagedObjectReference_Free(&task);
+ VIR_FREE(taskInfoErrorMessage);
esxVI_TaskInfo_Free(&taskInfo);
return result;
@@ -3472,7 +3480,8 @@ esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
const unsigned char *virtualMachineUuid,
esxVI_Occurrence virtualMachineOccurrence,
esxVI_Boolean autoAnswer,
- esxVI_TaskInfoState *finalState)
+ esxVI_TaskInfoState *finalState,
+ char **errorMessage)
{
int result = -1;
esxVI_ObjectSpec *objectSpec = NULL;
@@ -3489,6 +3498,11 @@ esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
esxVI_Boolean blocked = esxVI_Boolean_Undefined;
esxVI_TaskInfo *taskInfo = NULL;
+ if (errorMessage == NULL || *errorMessage != NULL) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+ return -1;
+ }
+
version = strdup("");
if (version == NULL) {
@@ -3609,6 +3623,35 @@ esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
goto cleanup;
}
+ if (*finalState != esxVI_TaskInfoState_Success) {
+ if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo)) {
+ goto cleanup;
+ }
+
+ if (taskInfo->error == NULL) {
+ *errorMessage = strdup(_("Unknown error"));
+
+ if (*errorMessage == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ } else if (taskInfo->error->localizedMessage == NULL) {
+ *errorMessage = strdup(taskInfo->error->fault->_actualType);
+
+ if (*errorMessage == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ } else {
+ if (virAsprintf(errorMessage, "%s - %s",
+ taskInfo->error->fault->_actualType,
+ taskInfo->error->localizedMessage) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+ }
+
result = 0;
cleanup:
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 26779ad..20e6fb5 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -429,7 +429,8 @@ int esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
const unsigned char *virtualMachineUuid,
esxVI_Occurrence virtualMachineOccurrence,
esxVI_Boolean autoAnswer,
- esxVI_TaskInfoState *finalState);
+ esxVI_TaskInfoState *finalState,
+ char **errorMessage);
int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
esxVI_HostCpuIdInfo *hostCpuIdInfo);
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 2ee513a..991ce8a 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -311,6 +311,12 @@ object LocalDatastoreInfo extends DatastoreInfo
end
+object LocalizedMethodFault
+ MethodFault fault r
+ String localizedMessage o
+end
+
+
object NasDatastoreInfo extends DatastoreInfo
HostNasVolume nas o
end
@@ -494,7 +500,7 @@ object TaskInfo
TaskInfoState state r
Boolean cancelled r
Boolean cancelable r
- LocalizedMethodFault error i
+ LocalizedMethodFault error o
AnyType result o
Int progress o
TaskReason reason i
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 4593379..4a8a9dc 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -1139,6 +1139,7 @@ predefined_objects = ["AnyType",
"Long",
"String",
"DateTime",
+ "MethodFault",
"ManagedObjectReference"]
@@ -1172,6 +1173,7 @@ additional_object_features = { "DatastoreHostMount" : Object.FEATURE__DE
removed_object_features = { "DynamicProperty" : Object.FEATURE__SERIALIZE,
+ "LocalizedMethodFault" : Object.FEATURE__SERIALIZE,
"ObjectContent" : Object.FEATURE__SERIALIZE,
"ObjectUpdate" : Object.FEATURE__SERIALIZE,
"PropertyChange" : Object.FEATURE__SERIALIZE,
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index ad45483..a70e1e0 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -701,6 +701,9 @@ esxVI_Type_ToString(esxVI_Type type)
case esxVI_Type_Fault:
return "Fault";
+ case esxVI_Type_MethodFault:
+ return "MethodFault";
+
case esxVI_Type_ManagedObjectReference:
return "ManagedObjectReference";
@@ -741,6 +744,8 @@ esxVI_Type_FromString(const char *type)
return esxVI_Type_DateTime;
} else if (STREQ(type, "Fault")) {
return esxVI_Type_Fault;
+ } else if (STREQ(type, "MethodFault")) {
+ return esxVI_Type_MethodFault;
} else if (STREQ(type, "ManagedObjectReference")) {
return esxVI_Type_ManagedObjectReference;
} else if (STREQ(type, "Datacenter")) {
@@ -751,7 +756,6 @@ esxVI_Type_FromString(const char *type)
return esxVI_Type_HostSystem;
}
-
#include "esx_vi_types.generated.typefromstring"
else {
@@ -1447,6 +1451,51 @@ ESX_VI__TEMPLATE__DESERIALIZE(Fault,
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: MethodFault
+ */
+
+/* esxVI_MethodFault_Alloc */
+ESX_VI__TEMPLATE__ALLOC(MethodFault);
+
+/* esxVI_MethodFault_Free */
+ESX_VI__TEMPLATE__FREE(MethodFault,
+{
+ VIR_FREE(item->_actualType);
+})
+
+int
+esxVI_MethodFault_Deserialize(xmlNodePtr node, esxVI_MethodFault **methodFault)
+{
+ if (methodFault == NULL || *methodFault != NULL) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+ return -1;
+ }
+
+ if (esxVI_MethodFault_Alloc(methodFault) < 0) {
+ return -1;
+ }
+
+ (*methodFault)->_actualType =
+ (char *)xmlGetNsProp(node, BAD_CAST "type",
+ BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
+
+ if ((*methodFault)->_actualType == NULL) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("MethodFault is missing 'type' property"));
+ goto failure;
+ }
+
+ return 0;
+
+ failure:
+ esxVI_MethodFault_Free(methodFault);
+
+ return -1;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VI Type: ManagedObjectReference
*/
diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h
index 901eda0..64bf2dc 100644
--- a/src/esx/esx_vi_types.h
+++ b/src/esx/esx_vi_types.h
@@ -48,6 +48,7 @@ typedef struct _esxVI_DateTime esxVI_DateTime;
*/
typedef struct _esxVI_Fault esxVI_Fault;
+typedef struct _esxVI_MethodFault esxVI_MethodFault;
typedef struct _esxVI_ManagedObjectReference esxVI_ManagedObjectReference;
typedef struct _esxVI_Datacenter esxVI_Datacenter;
typedef struct _esxVI_ComputeResource esxVI_ComputeResource;
@@ -71,6 +72,7 @@ enum _esxVI_Type {
esxVI_Type_Long,
esxVI_Type_DateTime,
esxVI_Type_Fault,
+ esxVI_Type_MethodFault,
esxVI_Type_ManagedObjectReference,
esxVI_Type_Datacenter,
esxVI_Type_ComputeResource,
@@ -279,6 +281,29 @@ int esxVI_Fault_Deserialize(xmlNodePtr node, esxVI_Fault **fault);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: MethodFault
+ */
+
+/*
+ * FIXME: This is just a minimal implementation of the MethodFault type.
+ * A complete implementation would require to implement dozens of
+ * extending types too.
+ */
+struct _esxVI_MethodFault {
+ esxVI_MethodFault *_unused; /* optional */
+ esxVI_Type _type; /* required */
+
+ char *_actualType; /* required */
+};
+
+int esxVI_MethodFault_Alloc(esxVI_MethodFault **methodfault);
+void esxVI_MethodFault_Free(esxVI_MethodFault **methodFault);
+int esxVI_MethodFault_Deserialize(xmlNodePtr node,
+ esxVI_MethodFault **methodFault);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VI Type: ManagedObjectReference
*/
--
1.7.0.4
14 years