diff --git a/cfg.mk b/cfg.mk index bda8c57b8d..03186b3015 100644 --- a/cfg.mk +++ b/cfg.mk @@ -388,6 +388,7 @@ msg_gen_function += virXMLError msg_gen_function += virXenInotifyError msg_gen_function += virXenStoreError msg_gen_function += virXendError +msg_gen_function += vmwareError msg_gen_function += xenapiSessionErrorHandler msg_gen_function += xenUnifiedError msg_gen_function += xenXMError diff --git a/configure.ac b/configure.ac index a52a03c2af..7a53c7d78c 100644 --- a/configure.ac +++ b/configure.ac @@ -227,6 +227,8 @@ AC_ARG_WITH([uml], AC_HELP_STRING([--with-uml], [add UML support @<:@default=check@:>@]),[],[with_uml=check]) AC_ARG_WITH([openvz], AC_HELP_STRING([--with-openvz], [add OpenVZ support @<:@default=yes@:>@]),[],[with_openvz=yes]) +AC_ARG_WITH([vmware], + AC_HELP_STRING([--with-vmware], [add VMware support @<:@default=yes@:>@]),[],[with_vmware=yes]) AC_ARG_WITH([libssh2], AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes]) AC_ARG_WITH([phyp], @@ -316,6 +318,10 @@ if test "$with_openvz" = "yes"; then fi AM_CONDITIONAL([WITH_OPENVZ], [test "$with_openvz" = "yes"]) +if test "$with_vmware" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_VMWARE], 1, [whether VMware driver is enabled]) +fi +AM_CONDITIONAL([WITH_VMWARE], [test "$with_vmware" = "yes"]) dnl dnl check for XDR @@ -2271,6 +2277,7 @@ AC_MSG_NOTICE([ Xen: $with_xen]) AC_MSG_NOTICE([ QEMU: $with_qemu]) AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) +AC_MSG_NOTICE([ VMware: $with_vmware]) AC_MSG_NOTICE([ VBox: $with_vbox]) AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index eaeb477ba2..a1f88f40f3 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -52,6 +52,7 @@ typedef enum { VIR_FROM_TEST, /* Error from test driver */ VIR_FROM_REMOTE, /* Error from remote driver */ VIR_FROM_OPENVZ, /* Error from OpenVZ driver */ + VIR_FROM_VMWARE, /* Error from VMware driver */ VIR_FROM_XENXM, /* Error at Xen XM layer */ VIR_FROM_STATS_LINUX,/* Error in the Linux Stats code */ VIR_FROM_LXC, /* Error from Linux Container driver */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 355df0b6cb..090de3b936 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -106,6 +106,8 @@ src/util/xml.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c src/vbox/vbox_tmpl.c +src/vmware/vmware_conf.c +src/vmware/vmware_driver.c src/xen/xen_driver.c src/xen/xen_hypervisor.c src/xen/xen_inotify.c diff --git a/src/Makefile.am b/src/Makefile.am index 55d96df33a..0f28f46290 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -219,8 +219,6 @@ check-local: remote_protocol-structs TEST_DRIVER_SOURCES = \ test/test_driver.c test/test_driver.h - - # Now the Hypervisor specific drivers XEN_DRIVER_SOURCES = \ xen/sexpr.c xen/sexpr.h \ @@ -256,6 +254,10 @@ OPENVZ_DRIVER_SOURCES = \ openvz/openvz_conf.c openvz/openvz_conf.h \ openvz/openvz_driver.c openvz/openvz_driver.h +VMWARE_DRIVER_SOURCES = \ + vmware/vmware_driver.c vmware/vmware.h \ + vmware/vmware_conf.c vmware/vmware_conf.h + VBOX_DRIVER_SOURCES = \ vbox/vbox_XPCOMCGlue.c vbox/vbox_XPCOMCGlue.h \ vbox/vbox_driver.c vbox/vbox_driver.h \ @@ -608,6 +610,21 @@ endif libvirt_driver_openvz_la_SOURCES = $(OPENVZ_DRIVER_SOURCES) endif +if WITH_VMWARE +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_vmware.la +else +noinst_LTLIBRARIES += libvirt_driver_vmware.la +libvirt_la_BUILT_LIBADD += libvirt_driver_vmware.la +endif +libvirt_driver_vmware_la_CFLAGS = \ + -I@top_srcdir@/src/conf +if WITH_DRIVER_MODULES +libvirt_driver_vmware_la_LDFLAGS = -module -avoid-version +endif +libvirt_driver_vmware_la_SOURCES = $(VMWARE_DRIVER_SOURCES) +endif + if WITH_VBOX if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_vbox.la @@ -960,7 +977,8 @@ EXTRA_DIST += \ $(SECURITY_DRIVER_SELINUX_SOURCES) \ $(SECURITY_DRIVER_APPARMOR_SOURCES) \ $(SECRET_DRIVER_SOURCES) \ - $(VBOX_DRIVER_EXTRA_DIST) + $(VBOX_DRIVER_EXTRA_DIST) \ + $(VMWARE_DRIVER_SOURCES) check-local: augeas-check diff --git a/src/driver.h b/src/driver.h index 75305fede5..03a388ad12 100644 --- a/src/driver.h +++ b/src/driver.h @@ -27,7 +27,8 @@ typedef enum { VIR_DRV_ONE = 9, VIR_DRV_ESX = 10, VIR_DRV_PHYP = 11, - VIR_DRV_XENAPI = 12 + VIR_DRV_XENAPI = 12, + VIR_DRV_VMWARE = 13 } virDrvNo; diff --git a/src/libvirt.c b/src/libvirt.c index ff2ac93857..ee2495a84e 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -54,6 +54,9 @@ # ifdef WITH_OPENVZ # include "openvz/openvz_driver.h" # endif +# ifdef WITH_VMWARE +# include "vmware/vmware_driver.h" +# endif # ifdef WITH_PHYP # include "phyp/phyp_driver.h" # endif @@ -365,6 +368,9 @@ virInitialize(void) # ifdef WITH_OPENVZ virDriverLoadModule("openvz"); # endif +# ifdef WITH_VMWARE + virDriverLoadModule("vmware"); +# endif # ifdef WITH_VBOX virDriverLoadModule("vbox"); # endif @@ -387,6 +393,9 @@ virInitialize(void) # ifdef WITH_OPENVZ if (openvzRegister() == -1) return -1; # endif +# ifdef WITH_VMWARE + if (vmwareRegister() == -1) return -1; +# endif # ifdef WITH_PHYP if (phypRegister() == -1) return -1; # endif @@ -1120,6 +1129,10 @@ virGetVersion(unsigned long *libVer, const char *type, if (STRCASEEQ(type, "OpenVZ")) *typeVer = LIBVIR_VERSION_NUMBER; # endif +# if WITH_VMWARE + if (STRCASEEQ(type, "VMware")) + *typeVer = LIBVIR_VERSION_NUMBER; +# endif # if WITH_VBOX if (STRCASEEQ(type, "VBox")) *typeVer = LIBVIR_VERSION_NUMBER; diff --git a/src/util/virterror.c b/src/util/virterror.c index b912737695..96a09cc00e 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -134,6 +134,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_OPENVZ: dom = "OpenVZ "; break; + case VIR_FROM_VMWARE: + dom = "VMware "; + break; case VIR_FROM_XENXM: dom = "Xen XM "; break; diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c new file mode 100644 index 0000000000..41747c9004 --- /dev/null +++ b/src/vmware/vmware_conf.c @@ -0,0 +1,500 @@ +/*---------------------------------------------------------------------------*/ +/* Copyright 2010, diateam (www.diateam.net) + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/*---------------------------------------------------------------------------*/ + +#include + +#include +#include + +#include "command.h" +#include "cpu/cpu.h" +#include "dirname.h" +#include "memory.h" +#include "nodeinfo.h" +#include "util/files.h" +#include "uuid.h" +#include "virterror_internal.h" +#include "../esx/esx_vmx.h" + +#include "vmware_conf.h" + +/* Free all memory associated with a vmware_driver structure */ +void +vmwareFreeDriver(struct vmware_driver *driver) +{ + if (!driver) + return; + + virMutexDestroy(&driver->lock); + virDomainObjListDeinit(&driver->domains); + virCapabilitiesFree(driver->caps); + VIR_FREE(driver); +} + +virCapsPtr +vmwareCapsInit(void) +{ + struct utsname utsname; + virCapsPtr caps = NULL; + virCapsGuestPtr guest = NULL; + virCPUDefPtr cpu = NULL; + union cpuData *data = NULL; + + uname(&utsname); + + if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) + goto error; + + if (nodeCapsInitNUMA(caps) < 0) + goto error; + + virCapabilitiesSetMacPrefix(caps, (unsigned char[]) {0x52, 0x54, 0x00}); + + /* i686 guests are always supported */ + if ((guest = virCapabilitiesAddGuest(caps, + "hvm", + "i686", + 32, + NULL, NULL, 0, NULL)) == NULL) + goto error; + + if (virCapabilitiesAddGuestDomain(guest, + "vmware", + NULL, NULL, 0, NULL) == NULL) + goto error; + + if (VIR_ALLOC(cpu) < 0 + || !(cpu->arch = strdup(utsname.machine))) { + virReportOOMError(); + goto error; + } + + cpu->type = VIR_CPU_TYPE_HOST; + + if (!(data = cpuNodeData(cpu->arch)) + || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { + goto error; + } + + /* x86_64 guests are supported if + * - Host arch is x86_64 + * Or + * - Host CPU is x86_64 with virtualization extensions + */ + if (STREQ(utsname.machine, "x86_64") || + (cpuHasFeature(utsname.machine, data, "lm") && + (cpuHasFeature(utsname.machine, data, "vmx") || + cpuHasFeature(utsname.machine, data, "svm")))) { + + if ((guest = virCapabilitiesAddGuest(caps, + "hvm", + "x86_64", + 64, + NULL, NULL, 0, NULL)) == NULL) + goto error; + + if (virCapabilitiesAddGuestDomain(guest, + "vmware", + NULL, NULL, 0, NULL) == NULL) + goto error; + } + +cleanup: + virCPUDefFree(cpu); + cpuDataFree(utsname.machine, data); + + return caps; + +error: + virCapabilitiesFree(caps); + goto cleanup; +} + +int +vmwareLoadDomains(struct vmware_driver *driver) +{ + virDomainDefPtr vmdef = NULL; + virDomainObjPtr vm = NULL; + char *vmxPath = NULL; + char *vmx = NULL; + vmwareDomainPtr pDomain; + char *directoryName = NULL; + char *fileName = NULL; + int ret = -1; + esxVMX_Context ctx; + char *outbuf = NULL; + char *str; + char *saveptr = NULL; + virCommandPtr cmd; + + ctx.parseFileName = esxCopyVMXFileName; + + cmd = virCommandNewArgList(VMRUN, "-T", + driver->type == TYPE_PLAYER ? "player" : "ws", + "list", NULL); + virCommandSetOutputBuffer(cmd, &outbuf); + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + for(str = outbuf ; (vmxPath = strtok_r(str, "\n", &saveptr)) != NULL; + str = NULL) { + + if (vmxPath[0] != '/') + continue; + + if (virFileReadAll(vmxPath, 10000, &vmx) < 0) + goto cleanup; + + if ((vmdef = + esxVMX_ParseConfig(&ctx, driver->caps, vmx, + esxVI_ProductVersion_ESX4x)) == NULL) { + goto cleanup; + } + + if (!(vm = virDomainAssignDef(driver->caps, + &driver->domains, vmdef, false))) + goto cleanup; + + pDomain = vm->privateData; + + pDomain->vmxPath = strdup(vmxPath); + if (pDomain->vmxPath == NULL) { + virReportOOMError(); + goto cleanup; + } + + vmwareDomainConfigDisplay(pDomain, vmdef); + + if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) + goto cleanup; + /* vmrun list only reports running vms */ + vm->state = VIR_DOMAIN_RUNNING; + vm->persistent = 1; + + virDomainObjUnlock(vm); + + vmdef = NULL; + vm = NULL; + } + + ret = 0; + +cleanup: + virCommandFree(cmd); + VIR_FREE(outbuf); + virDomainDefFree(vmdef); + VIR_FREE(directoryName); + VIR_FREE(fileName); + VIR_FREE(vmx); + if (vm) + virDomainObjUnref(vm); + return ret; +} + +void +vmwareSetSentinal(const char **prog, const char *key) +{ + const char **tmp = prog; + + while (tmp && *tmp) { + if (*tmp == PROGRAM_SENTINAL) { + *tmp = key; + break; + } + tmp++; + } +} + +int +vmwareExtractVersion(struct vmware_driver *driver) +{ + unsigned long version = 0; + char *tmp; + int ret = -1; + virCommandPtr cmd; + char * outbuf = NULL; + const char * bin = (driver->type == TYPE_PLAYER) ? "vmplayer" : "vmware"; + const char * pattern = (driver->type == TYPE_PLAYER) ? + "VMware Player " : "VMware Workstation "; + + cmd = virCommandNewArgList(bin, "-v", NULL); + virCommandSetOutputBuffer(cmd, &outbuf); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + if ((tmp = STRSKIP(outbuf, pattern)) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse %s version"), bin); + goto cleanup; + } + + if (virParseVersionString(tmp, &version) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("version parsing error")); + goto cleanup; + } + + driver->version = version; + ret = 0; + +cleanup: + virCommandFree(cmd); + VIR_FREE(outbuf); + return ret; +} + +int +vmwareDomainConfigDisplay(vmwareDomainPtr pDomain, virDomainDefPtr def) +{ + int i = 0; + + if (def->ngraphics == 0) { + pDomain->gui = true; + return 0; + } else { + pDomain->gui = false; + for (i = 0; i < def->ngraphics; i++) { + if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) { + pDomain->gui = true; + return 0; + } + } + return 0; + } +} + +int +vmwareParsePath(char *path, char **directory, char **filename) +{ + char *separator; + + separator = strrchr(path, '/'); + + if (separator != NULL) { + *separator++ = '\0'; + + if (*separator == '\0') { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("path '%s' doesn't reference a file"), path); + return -1; + } + + if ((*directory = strdup(path)) == NULL) + goto no_memory; + if ((*filename = strdup(separator)) == NULL) { + VIR_FREE(*directory); + goto no_memory; + } + + } else { + if ((*filename = strdup(path)) == NULL) + goto no_memory; + } + + return 0; + +no_memory: + virReportOOMError(); + return -1; +} + +int +vmwareConstructVmxPath(char *directoryName, char *name, char **vmxPath) +{ + if (directoryName != NULL) { + if (virAsprintf(vmxPath, "%s/%s.vmx", directoryName, name) < 0) { + virReportOOMError(); + return -1; + } + } else { + if (virAsprintf(vmxPath, "%s.vmx", name) < 0) { + virReportOOMError(); + return -1; + } + } + return 0; +} + +int +vmwareVmxPath(virDomainDefPtr vmdef, char **vmxPath) +{ + virDomainDiskDefPtr disk = NULL; + char *directoryName = NULL; + char *fileName = NULL; + int ret = -1; + int i = 0; + + /* + * Build VMX URL. Use the source of the first file-based harddisk + * to deduce the path for the VMX file. Don't just use the + * first disk, because it may be CDROM disk and ISO images are normaly not + * located in the virtual machine's directory. This approach + * isn't perfect but should work in the majority of cases. + */ + if (vmdef->ndisks < 1) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Domain XML doesn't contain any disks, " + "cannot deduce datastore and path for VMX file")); + goto cleanup; + } + + for (i = 0; i < vmdef->ndisks; ++i) { + if (vmdef->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK && + vmdef->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE) { + disk = vmdef->disks[i]; + break; + } + } + + if (disk == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Domain XML doesn't contain any file-based harddisks, " + "cannot deduce datastore and path for VMX file")); + goto cleanup; + } + + if (disk->src == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("First file-based harddisk has no source, cannot " + "deduce datastore and path for VMX file")); + goto cleanup; + } + + if (vmwareParsePath(disk->src, &directoryName, &fileName) < 0) { + goto cleanup; + } + + if (!virFileHasSuffix(fileName, ".vmdk")) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("Expecting source '%s' of first file-based harddisk " + "to be a VMDK image"), disk->src); + goto cleanup; + } + + if (vmwareConstructVmxPath(directoryName, vmdef->name, vmxPath) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(directoryName); + VIR_FREE(fileName); + return ret; +} + +int +vmwareMoveFile(char *srcFile, char *dstFile) +{ + const char *cmdmv[] = + { "mv", PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL }; + + if (!virFileExists(srcFile)) { + vmwareError(VIR_ERR_INTERNAL_ERROR, _("file %s does not exist"), + srcFile); + return -1; + } + + if (STREQ(srcFile, dstFile)) + return 0; + + vmwareSetSentinal(cmdmv, srcFile); + vmwareSetSentinal(cmdmv, dstFile); + if (virRun(cmdmv, NULL) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("failed to move file to %s "), dstFile); + return -1; + } + + return 0; +} + +int +vmwareMakePath(char *srcDir, char *srcName, char *srcExt, char **outpath) +{ + if (virAsprintf(outpath, "%s/%s.%s", srcDir, srcName, srcExt) < 0) { + virReportOOMError(); + return -1; + } + return 0; +} + +int +vmwareExtractPid(const char * vmxPath) +{ + char *vmxDir = NULL; + char *logFilePath = NULL; + FILE *logFile = NULL; + char line[1024]; + char *tmp = NULL; + int pid = -1; + + if ((vmxDir = mdir_name(vmxPath)) == NULL) + goto cleanup; + + if (virAsprintf(&logFilePath, "%s/vmware.log", + vmxDir) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((logFile = fopen(logFilePath, "r")) == NULL) + goto cleanup; + + if (!fgets(line, sizeof(line), logFile)) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unable to read vmware log file")); + goto cleanup; + } + + if ((tmp = strstr(line, " pid=")) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot find pid in vmware log file")); + goto cleanup; + } + + tmp += strlen(" pid="); + + if (virStrToLong_i(tmp, &tmp, 10, &pid) < 0 || *tmp != ' ') { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot parse pid in vmware log file")); + goto cleanup; + } + +cleanup: + VIR_FREE(vmxDir); + VIR_FREE(logFilePath); + VIR_FORCE_FCLOSE(logFile); + return pid; +} + +char * +esxCopyVMXFileName(const char *datastorePath, void *opaque ATTRIBUTE_UNUSED) +{ + char *path = strdup(datastorePath); + + if (path == NULL) { + virReportOOMError(); + return NULL; + } + + return path; +} diff --git a/src/vmware/vmware_conf.h b/src/vmware/vmware_conf.h new file mode 100644 index 0000000000..b1cdf8fea4 --- /dev/null +++ b/src/vmware/vmware_conf.h @@ -0,0 +1,83 @@ +/*---------------------------------------------------------------------------*/ +/* Copyright 2010, diateam (www.diateam.net) + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/*---------------------------------------------------------------------------*/ + +#ifndef VMWARE_CONF_H +# define VMWARE_CONF_H + +# define VMRUN "vmrun" +# define NOGUI "nogui" + +# include "internal.h" +# include "domain_conf.h" +# include "threads.h" + +# define VIR_FROM_THIS VIR_FROM_VMWARE +# define PROGRAM_SENTINAL ((char *)0x1) + +# define vmwareError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_VMWARE, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +# define TYPE_PLAYER 0 +# define TYPE_WORKSTATION 1 + +struct vmware_driver { + virMutex lock; + virCapsPtr caps; + + virDomainObjList domains; + int version; + int type; +}; + +typedef struct _vmwareDomain { + char *vmxPath; + bool gui; + +} vmwareDomain, *vmwareDomainPtr; + +void vmwareFreeDriver(struct vmware_driver *driver); + +virCapsPtr vmwareCapsInit(void); + +int vmwareLoadDomains(struct vmware_driver *driver); + +void vmwareSetSentinal(const char **prog, const char *key); + +int vmwareExtractVersion(struct vmware_driver *driver); + +int vmwareDomainConfigDisplay(vmwareDomainPtr domain, virDomainDefPtr vmdef); + +int vmwareParsePath(char *path, char **directory, char **filename); + +int vmwareConstructVmxPath(char *directoryName, char *name, + char **vmxPath); + +int vmwareVmxPath(virDomainDefPtr vmdef, char **vmxPath); + +int vmwareMoveFile(char *srcFile, char *dstFile); + +int vmwareMakePath(char *srcDir, char *srcName, char *srcExt, + char **outpath); + +int vmwareExtractPid(const char * vmxPath); + +char * esxCopyVMXFileName(const char *datastorePath, void *opaque); + +#endif diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c new file mode 100644 index 0000000000..9662f4607e --- /dev/null +++ b/src/vmware/vmware_driver.c @@ -0,0 +1,1013 @@ +/*---------------------------------------------------------------------------*/ +/* Copyright 2010, diateam (www.diateam.net) + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/*---------------------------------------------------------------------------*/ + +#include + +#include + +#include "files.h" +#include "memory.h" +#include "uuid.h" + +#include "../esx/esx_vmx.h" +#include "vmware_conf.h" +#include "vmware_driver.h" + +const char *vmw_types[] = { "player", "ws" }; + +static void +vmwareDriverLock(struct vmware_driver *driver) +{ + virMutexLock(&driver->lock); +} + +static void +vmwareDriverUnlock(struct vmware_driver *driver) +{ + virMutexUnlock(&driver->lock); +} + +static void * +vmwareDataAllocFunc(void) +{ + vmwareDomainPtr dom; + + if (VIR_ALLOC(dom) < 0) + return NULL; + + dom->vmxPath = NULL; + dom->gui = true; + + return dom; +} + +static void +vmwareDataFreeFunc(void *data) +{ + vmwareDomainPtr dom = data; + + VIR_FREE(dom->vmxPath); + VIR_FREE(dom); +} + +static virDrvOpenStatus +vmwareOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + struct vmware_driver *driver; + char * vmrun = NULL; + + if (conn->uri == NULL) { + /* @TODO accept */ + return VIR_DRV_OPEN_DECLINED; + } else { + if (conn->uri->scheme == NULL || + (STRNEQ(conn->uri->scheme, "vmwareplayer") && + STRNEQ(conn->uri->scheme, "vmwarews"))) + return VIR_DRV_OPEN_DECLINED; + + /* If server name is given, its for remote driver */ + if (conn->uri->server != NULL) + return VIR_DRV_OPEN_DECLINED; + + /* If path isn't /session, then they typoed, so tell them correct path */ + if (conn->uri->path == NULL || STRNEQ(conn->uri->path, "/session")) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("unexpected VMware URI path '%s', try vmwareplayer:///session or vmwarews:///session"), + NULLSTR(conn->uri->path)); + return VIR_DRV_OPEN_ERROR; + } + } + + /* We now know the URI is definitely for this driver, so beyond + * here, don't return DECLINED, always use ERROR */ + + vmrun = virFindFileInPath(VMRUN); + + if (vmrun == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("%s utility is missing"), VMRUN); + return VIR_DRV_OPEN_ERROR; + } else { + VIR_FREE(vmrun); + } + + if (VIR_ALLOC(driver) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + + if (virMutexInit(&driver->lock) < 0) + goto cleanup; + + driver->type = STRNEQ(conn->uri->scheme, "vmwareplayer") ? + TYPE_WORKSTATION : TYPE_PLAYER; + + if (virDomainObjListInit(&driver->domains) < 0) + goto cleanup; + + if (!(driver->caps = vmwareCapsInit())) + goto cleanup; + + driver->caps->privateDataAllocFunc = vmwareDataAllocFunc; + driver->caps->privateDataFreeFunc = vmwareDataFreeFunc; + + if (vmwareLoadDomains(driver) < 0) + goto cleanup; + + if (vmwareExtractVersion(driver) < 0) + goto cleanup; + + conn->privateData = driver; + + return VIR_DRV_OPEN_SUCCESS; + + cleanup: + vmwareFreeDriver(driver); + return VIR_DRV_OPEN_ERROR; +}; + +static int +vmwareClose(virConnectPtr conn) +{ + struct vmware_driver *driver = conn->privateData; + + vmwareFreeDriver(driver); + + conn->privateData = NULL; + + return 0; +} + +static const char * +vmwareGetType(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "VMware"; +} + +static int +vmwareGetVersion(virConnectPtr conn, unsigned long *version) +{ + struct vmware_driver *driver = conn->privateData; + + vmwareDriverLock(driver); + *version = driver->version; + vmwareDriverUnlock(driver); + return 0; +} + +static int +vmwareStopVM(struct vmware_driver *driver, virDomainObjPtr vm) +{ + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "stop", + PROGRAM_SENTINAL, "soft", NULL + }; + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath); + + if (virRun(cmd, NULL) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VMRUN); + return -1; + } + + vm->def->id = -1; + vm->state = VIR_DOMAIN_SHUTOFF; + + return 0; +} + +static int +vmwareStartVM(struct vmware_driver *driver, virDomainObjPtr vm) +{ + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "start", + PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL + }; + const char *vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath; + + if (vm->state != VIR_DOMAIN_SHUTOFF) { + vmwareError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain is not in shutoff state")); + return -1; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, vmxPath); + if (!((vmwareDomainPtr) vm->privateData)->gui) + vmwareSetSentinal(cmd, NOGUI); + else + vmwareSetSentinal(cmd, NULL); + + if (virRun(cmd, NULL) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VMRUN); + return -1; + } + + if ((vm->def->id = vmwareExtractPid(vmxPath)) < 0) { + vmwareStopVM(driver, vm); + return -1; + } + + vm->state = VIR_DOMAIN_RUNNING; + + return 0; +} + +static virDomainPtr +vmwareDomainDefineXML(virConnectPtr conn, const char *xml) +{ + struct vmware_driver *driver = conn->privateData; + virDomainDefPtr vmdef = NULL; + virDomainObjPtr vm = NULL; + virDomainPtr dom = NULL; + char *vmx = NULL; + char *directoryName = NULL; + char *fileName = NULL; + char *vmxPath = NULL; + vmwareDomainPtr pDomain = NULL; + esxVMX_Context ctx; + + ctx.formatFileName = esxCopyVMXFileName; + + vmwareDriverLock(driver); + if ((vmdef = virDomainDefParseString(driver->caps, xml, + VIR_DOMAIN_XML_INACTIVE)) == NULL) + goto cleanup; + + if (virDomainObjIsDuplicate(&driver->domains, vmdef, 1) < 0) + goto cleanup; + + /* generate vmx file */ + vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef, + esxVI_ProductVersion_ESX4x); + if (vmx == NULL) + goto cleanup; + + if (vmwareVmxPath(vmdef, &vmxPath) < 0) + goto cleanup; + + /* create vmx file */ + if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("Failed to write vmx file '%s'"), vmxPath); + goto cleanup; + } + + /* assign def */ + if (!(vm = virDomainAssignDef(driver->caps, + &driver->domains, vmdef, false))) + goto cleanup; + + pDomain = vm->privateData; + if ((pDomain->vmxPath = strdup(vmxPath)) == NULL) { + virReportOOMError(); + goto cleanup; + } + + vmwareDomainConfigDisplay(pDomain, vmdef); + + vmdef = NULL; + vm->persistent = 1; + + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); + if (dom) + dom->id = -1; + + cleanup: + virDomainDefFree(vmdef); + VIR_FREE(vmx); + VIR_FREE(directoryName); + VIR_FREE(fileName); + VIR_FREE(vmxPath); + if (vm) + virDomainObjUnlock(vm); + vmwareDriverUnlock(driver); + return dom; +} + +static int +vmwareDomainShutdown(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + vmwareDriverLock(driver); + + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + if (vm->state != VIR_DOMAIN_RUNNING) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("domain is not in running state")); + goto cleanup; + } + + if (vmwareStopVM(driver, vm) < 0) + goto cleanup; + + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + + ret = 0; + cleanup: + if (vm) + virDomainObjUnlock(vm); + vmwareDriverUnlock(driver); + return ret; +} + +static int +vmwareDomainSuspend(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + + virDomainObjPtr vm; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "pause", + PROGRAM_SENTINAL, NULL + }; + int ret = -1; + + if (driver->type == TYPE_PLAYER) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("vmplayer does not support libvirt suspend/resume" + " (vmware pause/unpause) operation ")); + return ret; + } + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath); + if (vm->state != VIR_DOMAIN_RUNNING) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("domain is not in running state")); + goto cleanup; + } + + if (virRun(cmd, NULL) < 0) + goto cleanup; + + vm->state = VIR_DOMAIN_PAUSED; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +vmwareDomainResume(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + + virDomainObjPtr vm; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "unpause", PROGRAM_SENTINAL, + NULL + }; + int ret = -1; + + if (driver->type == TYPE_PLAYER) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("vmplayer does not support libvirt suspend/resume" + "(vmware pause/unpause) operation ")); + return ret; + } + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath); + if (vm->state != VIR_DOMAIN_PAUSED) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("domain is not in suspend state")); + goto cleanup; + } + + if (virRun(cmd, NULL) < 0) + goto cleanup; + + vm->state = VIR_DOMAIN_RUNNING; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +vmwareDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + struct vmware_driver *driver = dom->conn->privateData; + const char * vmxPath = NULL; + + virDomainObjPtr vm; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, + "reset", PROGRAM_SENTINAL, "soft", NULL + }; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + vmxPath = ((vmwareDomainPtr) vm->privateData)->vmxPath; + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((vmwareDomainPtr) vm->privateData)->vmxPath); + + + if (vm->state != VIR_DOMAIN_RUNNING) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("domain is not in running state")); + goto cleanup; + } + + if (virRun(cmd, NULL) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static virDomainPtr +vmwareDomainCreateXML(virConnectPtr conn, const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct vmware_driver *driver = conn->privateData; + virDomainDefPtr vmdef = NULL; + virDomainObjPtr vm = NULL; + virDomainPtr dom = NULL; + char *vmx = NULL; + char *vmxPath = NULL; + vmwareDomainPtr pDomain = NULL; + esxVMX_Context ctx; + + ctx.formatFileName = esxCopyVMXFileName; + + vmwareDriverLock(driver); + + if ((vmdef = virDomainDefParseString(driver->caps, xml, + VIR_DOMAIN_XML_INACTIVE)) == NULL) + goto cleanup; + + if (virDomainObjIsDuplicate(&driver->domains, vmdef, 1) < 0) + goto cleanup; + + /* generate vmx file */ + vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef, + esxVI_ProductVersion_ESX4x); + if (vmx == NULL) + goto cleanup; + + if (vmwareVmxPath(vmdef, &vmxPath) < 0) + goto cleanup; + + /* create vmx file */ + if (virFileWriteStr(vmxPath, vmx, S_IRUSR|S_IWUSR) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("Failed to write vmx file '%s'"), vmxPath); + goto cleanup; + } + + /* assign def */ + if (!(vm = virDomainAssignDef(driver->caps, + &driver->domains, vmdef, false))) + goto cleanup; + + pDomain = vm->privateData; + pDomain->vmxPath = strdup(vmxPath); + + vmwareDomainConfigDisplay(pDomain, vmdef); + vmdef = NULL; + + if (vmwareStartVM(driver, vm) < 0) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + goto cleanup; + } + + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); + if (dom) + dom->id = vm->def->id; + +cleanup: + virDomainDefFree(vmdef); + VIR_FREE(vmx); + VIR_FREE(vmxPath); + if(vm) + virDomainObjUnlock(vm); + vmwareDriverUnlock(driver); + return dom; +} + +static int +vmwareDomainCreateWithFlags(virDomainPtr dom, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + vmwareError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (virDomainObjIsActive(vm)) { + vmwareError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is already running")); + goto cleanup; + } + + ret = vmwareStartVM(driver, vm); + +cleanup: + if (vm) + virDomainObjUnlock(vm); + vmwareDriverUnlock(driver); + return ret; +} + +static int +vmwareDomainCreate(virDomainPtr dom) +{ + return vmwareDomainCreateWithFlags(dom, 0); +} + +static int +vmwareDomainUndefine(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(dom->uuid, uuidstr); + vmwareError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (virDomainObjIsActive(vm)) { + vmwareError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot undefine active domain")); + goto cleanup; + } + + if (!vm->persistent) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot undefine transient domain")); + goto cleanup; + } + + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + vmwareDriverUnlock(driver); + return ret; +} + +static virDomainPtr +vmwareDomainLookupByID(virConnectPtr conn, int id) +{ + struct vmware_driver *driver = conn->privateData; + virDomainObjPtr vm; + virDomainPtr dom = NULL; + + vmwareDriverLock(driver); + vm = virDomainFindByID(&driver->domains, id); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); + if (dom) + dom->id = vm->def->id; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return dom; +} + +static char * +vmwareGetOSType(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + char *ret = NULL; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + + if (!(ret = strdup(vm->def->os.type))) + virReportOOMError(); + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + + +static virDomainPtr +vmwareDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) +{ + struct vmware_driver *driver = conn->privateData; + virDomainObjPtr vm; + virDomainPtr dom = NULL; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); + if (dom) + dom->id = vm->def->id; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return dom; +} + +static virDomainPtr +vmwareDomainLookupByName(virConnectPtr conn, const char *name) +{ + struct vmware_driver *driver = conn->privateData; + virDomainObjPtr vm; + virDomainPtr dom = NULL; + + vmwareDriverLock(driver); + vm = virDomainFindByName(&driver->domains, name); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + + dom = virGetDomain(conn, vm->def->name, vm->def->uuid); + if (dom) + dom->id = vm->def->id; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return dom; +} + +static int +vmwareDomainIsActive(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr obj; + int ret = -1; + + vmwareDriverLock(driver); + obj = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + if (!obj) { + vmwareError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + ret = virDomainObjIsActive(obj); + + cleanup: + if (obj) + virDomainObjUnlock(obj); + return ret; +} + + +static int +vmwareDomainIsPersistent(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr obj; + int ret = -1; + + vmwareDriverLock(driver); + obj = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + if (!obj) { + vmwareError(VIR_ERR_NO_DOMAIN, NULL); + goto cleanup; + } + ret = obj->persistent; + + cleanup: + if (obj) + virDomainObjUnlock(obj); + return ret; +} + + +static char * +vmwareDomainDumpXML(virDomainPtr dom, int flags) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + char *ret = NULL; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + ret = virDomainDefFormat(vm->def, flags); + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +vmwareNumDefinedDomains(virConnectPtr conn) +{ + struct vmware_driver *driver = conn->privateData; + int n; + + vmwareDriverLock(driver); + n = virDomainObjListNumOfDomains(&driver->domains, 0); + vmwareDriverUnlock(driver); + + return n; +} + +static int +vmwareNumDomains(virConnectPtr conn) +{ + struct vmware_driver *driver = conn->privateData; + int n; + + vmwareDriverLock(driver); + n = virDomainObjListNumOfDomains(&driver->domains, 1); + vmwareDriverUnlock(driver); + + return n; +} + + +static int +vmwareListDomains(virConnectPtr conn, int *ids, int nids) +{ + struct vmware_driver *driver = conn->privateData; + int n; + + vmwareDriverLock(driver); + n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids); + vmwareDriverUnlock(driver); + + return n; +} + +static int +vmwareListDefinedDomains(virConnectPtr conn, + char **const names, int nnames) +{ + struct vmware_driver *driver = conn->privateData; + int n; + + vmwareDriverLock(driver); + n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames); + vmwareDriverUnlock(driver); + return n; +} + +static int +vmwareDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) +{ + struct vmware_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + info->state = vm->state; + info->cpuTime = 0; + info->maxMem = vm->def->mem.max_balloon; + info->memory = vm->def->mem.cur_balloon; + info->nrVirtCpu = vm->def->vcpus; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static virDriver vmwareDriver = { + VIR_DRV_VMWARE, + "VMWARE", + vmwareOpen, /* open */ + vmwareClose, /* close */ + NULL, /* supports_feature */ + vmwareGetType, /* type */ + vmwareGetVersion, /* version */ + NULL, /* libvirtVersion (impl. in libvirt.c) */ + NULL, /* getHostname */ + NULL, /* getMaxVcpus */ + NULL, /* nodeGetInfo */ + NULL, /* getCapabilities */ + vmwareListDomains, /* listDomains */ + vmwareNumDomains, /* numOfDomains */ + vmwareDomainCreateXML, /* domainCreateXML */ + vmwareDomainLookupByID, /* domainLookupByID */ + vmwareDomainLookupByUUID, /* domainLookupByUUID */ + vmwareDomainLookupByName, /* domainLookupByName */ + vmwareDomainSuspend, /* domainSuspend */ + vmwareDomainResume, /* domainResume */ + vmwareDomainShutdown, /* domainShutdown */ + vmwareDomainReboot, /* domainReboot */ + vmwareDomainShutdown, /* domainDestroy */ + vmwareGetOSType, /* domainGetOSType */ + NULL, /* domainGetMaxMemory */ + NULL, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + vmwareDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ + NULL, /* domainSetVcpusFlags */ + NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + NULL, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + vmwareDomainDumpXML, /* domainDumpXML */ + NULL, /* domainXmlFromNative */ + NULL, /* domainXmlToNative */ + vmwareListDefinedDomains, /* listDefinedDomains */ + vmwareNumDefinedDomains, /* numOfDefinedDomains */ + vmwareDomainCreate, /* domainCreate */ + vmwareDomainCreateWithFlags,/* domainCreateWithFlags */ + vmwareDomainDefineXML, /* domainDefineXML */ + vmwareDomainUndefine, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, /* domainAttachDeviceFlags */ + NULL, /* domainDetachDevice */ + NULL, /* domainDetachDeviceFlags */ + NULL, /* domainUpdateDeviceFlags */ + NULL, /* domainGetAutostart */ + NULL, /* domainSetAutostart */ + NULL, /* domainGetSchedulerType */ + NULL, /* domainGetSchedulerParameters */ + NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ + NULL, /* domainMemoryStats */ + NULL, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCellsFreeMemory */ + NULL, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + NULL, /* nodeDeviceDettach */ + NULL, /* nodeDeviceReAttach */ + NULL, /* nodeDeviceReset */ + NULL, /* domainMigratePrepareTunnel */ + NULL, /* IsEncrypted */ + NULL, /* IsSecure */ + vmwareDomainIsActive, /* DomainIsActive */ + vmwareDomainIsPersistent, /* DomainIsPersistent */ + NULL, /* domainIsUpdated */ + NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ + NULL, /* domainGetJobInfo */ + NULL, /* domainAbortJob */ + NULL, /* domainMigrateSetMaxDowntime */ + NULL, /* domainEventRegisterAny */ + NULL, /* domainEventDeregisterAny */ + NULL, /* domainManagedSave */ + NULL, /* domainHasManagedSaveImage */ + NULL, /* domainManagedSaveRemove */ + NULL, /* domainSnapshotCreateXML */ + NULL, /* domainSnapshotDumpXML */ + NULL, /* domainSnapshotNum */ + NULL, /* domainSnapshotListNames */ + NULL, /* domainSnapshotLookupByName */ + NULL, /* domainHasCurrentSnapshot */ + NULL, /* domainSnapshotCurrent */ + NULL, /* domainRevertToSnapshot */ + NULL, /* domainSnapshotDelete */ + NULL, /* qemuDomainMonitorCommand */ + NULL, /* domainSetMemoryParameters */ + NULL, /* domainGetMemoryParameters */ + NULL, /* domainOpenConsole */ +}; + +int +vmwareRegister(void) +{ + if (virRegisterDriver(&vmwareDriver) < 0) + return -1; + return 0; +} diff --git a/src/vmware/vmware_driver.h b/src/vmware/vmware_driver.h new file mode 100644 index 0000000000..71186de575 --- /dev/null +++ b/src/vmware/vmware_driver.h @@ -0,0 +1,25 @@ +/*---------------------------------------------------------------------------*/ +/* Copyright 2010, diateam (www.diateam.net) + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/*---------------------------------------------------------------------------*/ + +#ifndef VMWARE_DRIVER_H +# define VMWARE_DRIVER_H + +int vmwareRegister(void); + +#endif