On Sunday 14 November 2010 23:11:22 Matthias Bolte wrote: > 2010/11/12 Jean-Baptiste Rouault <jean-baptiste.rouault@xxxxxxxxxxx>: > > On Tuesday 27 July 2010 20:42:01 Matthias Bolte wrote: > >> We'll need to move the VMX handling code from src/esx to src/util, > >> because drivers are not allowed to depend on each other. > >> > >> That should be possible, but will require some refactoring, because > >> this code is currently closely entangled with the reset of the ESX > >> driver in some places and parts of it are probably quite ESX specific. > > > > Hi, > > > > As of today we have a "proof of concept" vmware driver with > > basic functions implemented (open/close, define/undefine, create, > > start/shutdown...) > > However it currently depends on the esx driver for the VMX handling code. > > Has anyone started to think of the needed refactoring ? If any help is > > needed to refactor I guess I could find some time to work on it. > > > > Jean-Baptiste > > A while ago I started to refactor some obviously ESX specific stuff > out of the VMX code into a callback mechanism. > > One thing I'm going to change is the product version handling. > > There should be no major problem left in the VMX code that could stop > it from being moved to src/util/. > > As you say you have some basic stuff working now, maybe it's a good > idea that you show you code here for an initial review and let me do > the refactoring once I can see how you use the VMX code. > > Matthias Here is the patch, I can try to split it if it's easier for the review. The major part of this patch was done by an old colleague of mine, there is still work and a bit of cleaning to do. Regards, Jean-Baptiste -- Jean-Baptiste ROUAULT IngÃnieur R&D - Diateam : Architectes de l'information Phone : +33 (0)9 53 16 02 70 Fax : +33 (0)2 98 050 051
From 328969ebae5d1b512b29c461d758b5896fb892fd Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Rouault <jean-baptiste.rouault@xxxxxxxxxxx> Date: Mon, 15 Nov 2010 16:01:11 +0100 Subject: [PATCH] Add VMware Workstation and Player driver --- configure.ac | 7 + include/libvirt/virterror.h | 1 + po/POTFILES.in | 2 + src/Makefile.am | 24 +- src/driver.h | 3 +- src/libvirt.c | 16 + src/util/virterror.c | 3 + src/vmware/vmware_conf.c | 447 ++++++++++++++ src/vmware/vmware_conf.h | 80 +++ src/vmware/vmware_driver.c | 1354 +++++++++++++++++++++++++++++++++++++++++++ src/vmware/vmware_driver.h | 27 + 11 files changed, 1960 insertions(+), 4 deletions(-) create mode 100644 src/vmware/vmware_conf.c create mode 100644 src/vmware/vmware_conf.h create mode 100644 src/vmware/vmware_driver.c create mode 100644 src/vmware/vmware_driver.h diff --git a/configure.ac b/configure.ac index d21d558..90b3181 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_wmware=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 @@ -2274,6 +2280,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 eaeb477..de05d0f 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 ed3a151..7af6fdb 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -98,6 +98,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 20c0c9f..3863d21 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -225,8 +225,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 \ @@ -262,6 +260,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 \ @@ -607,6 +609,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 @@ -959,7 +976,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 6417ee9..ebbdc40 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 3c8bf30..6bf490a 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -53,6 +53,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 @@ -364,6 +367,12 @@ virInitialize(void) # ifdef WITH_OPENVZ virDriverLoadModule("openvz"); # endif +# ifdef WITH_VMWARE + virDriverLoadModule("vmware"); +# endif +# ifdef WITH_VMWARE + virDriverLoadModule("vmware"); +# endif # ifdef WITH_VBOX virDriverLoadModule("vbox"); # endif @@ -386,6 +395,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 @@ -1119,6 +1131,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 9757fd4..988a9ad 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -133,6 +133,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 0000000..4036d9b --- /dev/null +++ b/src/vmware/vmware_conf.c @@ -0,0 +1,447 @@ +/*---------------------------------------------------------------------------*/ +/* 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 <config.h> + +#include <sys/utsname.h> + +#include "memory.h" +#include "nodeinfo.h" +#include "uuid.h" +#include "virterror_internal.h" + +#include "vmware_conf.h" + +#define VMWARE_MAX_ARG 20 + +/* Free all memory associated with a vmware_driver structure */ +void +vmwareFreeDriver(struct vmware_driver *driver) +{ + if (!driver) + return; + + virDomainObjListDeinit(&driver->domains); + virCapabilitiesFree(driver->caps); + VIR_FREE(driver); +} + +virCapsPtr +vmwareCapsInit(void) +{ + struct utsname utsname; + + virCapsPtr caps; + + virCapsGuestPtr guest; + + uname(&utsname); + + if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) + goto no_memory; + + if (nodeCapsInitNUMA(caps) < 0) + goto no_memory; + + virCapabilitiesSetMacPrefix(caps, (unsigned char[]) { + 0x52, 0x54, 0x00}); + + if ((guest = virCapabilitiesAddGuest(caps, + "hvm", + utsname.machine, + sizeof(int) == 4 ? 32 : 8, + NULL, NULL, 0, NULL)) == NULL) + goto no_memory; + + if (virCapabilitiesAddGuestDomain(guest, + "vmware", + NULL, NULL, 0, NULL) == NULL) + goto no_memory; + return caps; + + no_memory: + virCapabilitiesFree(caps); + return NULL; +} + +int +vmwareLoadDomains(struct vmware_driver *driver) +{ + FILE *fp; + + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virDomainObjPtr dom = NULL; + + char vmxPath[100]; + + pvmwareDomain pDomain; + + char *directoryName = NULL; + + char *fileName = NULL; + + char *separator = NULL; + + fp = driver->type == + TYPE_PLAYER ? popen(VMRUN " -T " "player" " list 2>/dev/null", + "r") : popen(VMRUN " -T " "ws" + " list 2>/dev/null", "r"); + if (fp == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("popen failed")); + return -1; + } + + while (!feof(fp)) { + if (fscanf(fp, "%s\n", vmxPath) != 1) { + if (feof(fp)) + break; + + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to parse vmrun list output")); + goto cleanup; + } + if (vmxPath[0] != '/') + continue; + + if (VIR_ALLOC(dom) < 0) + goto no_memory; + + if (virMutexInit(&dom->lock) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize mutex")); + VIR_FREE(dom); + goto cleanup; + } + printf("b\n"); + virDomainObjLock(dom); + + + //* save vmxpath in domain object * // + //pDomain = malloc(sizeof(vmwareDomain)); + //if(pDomain==NULL) { + if (VIR_ALLOC(pDomain) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, _("no memory ")); + goto cleanup; + } + pDomain->vmxPath = strdup(vmxPath); + dom->privateData = pDomain; + + + if (VIR_ALLOC(dom->def) < 0) + goto no_memory; + + //vmrun list only reports running vms + dom->state = VIR_DOMAIN_RUNNING; + + dom->refs = 1; + + //dom->def->id = + dom->persistent = 1; + /* name */ + if (vmwareParsePath(vmxPath, &directoryName, &fileName) < 0) { + goto cleanup; + } + separator = strrchr(fileName, '.'); + if (separator == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("name parsing error")); + goto cleanup; + } + *separator = '\0'; + if (virAsprintf(&dom->def->name, "%s", fileName) < 0) + goto no_memory; + + if (virUUIDGenerate(dom->def->uuid) < 0) + goto no_memory; + dom->def->vcpus = 1; + + virUUIDFormat(dom->def->uuid, uuidstr); + if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0) + goto no_memory; + + virDomainObjUnlock(dom); + dom = NULL; + } + + fclose(fp); + VIR_FREE(directoryName); + VIR_FREE(fileName); + + return 0; + + no_memory: + virReportOOMError(); + + cleanup: + fclose(fp); + VIR_FREE(directoryName); + VIR_FREE(fileName); + if (dom) + virDomainObjUnref(dom); + return -1; +} + +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; + + FILE *fp = NULL; + + char str[50]; + + char *tmp; + + if (driver->type == TYPE_PLAYER) { + if ((fp = popen("vmplayer -v 2>/dev/null", "r")) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", ("popen failed")); + return -1; + } + if (!feof(fp) && fgets(str, 49, fp)) { + if ((tmp = STRSKIP(str, "VMware Player ")) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + ("vmplayer -v parsing error")); + return -1; + } + if (virParseVersionString(tmp, &version) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + ("version parsing error")); + return -1; + } + driver->version = version; + return 0; + } + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + ("vmplayer -v reading error")); + } else if (driver->type == TYPE_WORKSTATION) { + if ((fp = popen("vmware -v 2>/dev/null", "r")) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", ("popen failed")); + return -1; + } + if (!feof(fp) && fgets(str, 49, fp)) { + if ((tmp = STRSKIP(str, "VMware Workstation ")) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + ("vmware -v parsing error")); + return -1; + } + if (virParseVersionString(tmp, &version) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + ("version parsing error")); + return -1; + } + driver->version = version; + return 0; + } + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + ("vmware -v reading error")); + } + return -1; +} + +int +vmwareDomainConfigDisplay(pvmwareDomain 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) { + printf("type desktop\n"); + 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; + } + + *directory = strdup(path); + *filename = strdup(separator); + + } else { + *filename = strdup(separator); + } + + return 0; +} + +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 }; + printf("mv %s %s\n", srcFile, dstFile); + 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; +} diff --git a/src/vmware/vmware_conf.h b/src/vmware/vmware_conf.h new file mode 100644 index 0000000..386ebf2 --- /dev/null +++ b/src/vmware/vmware_conf.h @@ -0,0 +1,80 @@ +/*---------------------------------------------------------------------------*/ +/* 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; + int z; + bool gui; + +} vmwareDomain, *pvmwareDomain; + +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(pvmwareDomain 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); + +#endif diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c new file mode 100644 index 0000000..7a40ae0 --- /dev/null +++ b/src/vmware/vmware_driver.c @@ -0,0 +1,1354 @@ +/*---------------------------------------------------------------------------*/ +/* 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 <config.h> + +#include <fcntl.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 +vmwareDataFreeFunc(void *blob) +{ + VIR_FREE(blob); +} + +static virDrvOpenStatus +vmwareOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + struct vmware_driver *driver; + + 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 /system, then they typoed, so tell them correct path */ + if (conn->uri->path == NULL || STRNEQ(conn->uri->path, "/system")) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + ("unexpected VMware URI path '%s', try vmwareplayer:///system or vmwarews:///system"), + 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 */ + + if (VIR_ALLOC(driver) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + + driver->type = STRNEQ(conn->uri->scheme, "vmwareplayer") ? + TYPE_WORKSTATION : TYPE_PLAYER; + + if (virDomainObjListInit(&driver->domains) < 0) + goto cleanup; + + if (!(driver->caps = vmwareCapsInit())) + goto cleanup; + + 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) +{ + struct vmware_driver *driver = conn->privateData; + + int type; + + vmwareDriverLock(driver); + type = driver->type; + vmwareDriverUnlock(driver); + return type == TYPE_PLAYER ? "vmware player" : "vmware workstation"; +} + +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 +vmwareDomainCreate(virDomainPtr dom) +{ + int ret = -1; + + struct vmware_driver *driver = dom->conn->privateData; + + virDomainObjPtr vm; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "start", + PROGRAM_SENTINAL, PROGRAM_SENTINAL, NULL + }; + + vmwareDriverLock(driver); + vm = virDomainFindByName(&driver->domains, dom->name); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_INVALID_DOMAIN, "%s", + _("no domain with matching id")); + goto cleanup; + } + + if (vm->state != VIR_DOMAIN_SHUTOFF) { + vmwareError(VIR_ERR_OPERATION_DENIED, "%s", + _("domain is not in shutoff state")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((pvmwareDomain) vm->privateData)->vmxPath); + if (((pvmwareDomain) vm->privateData)->gui == false) + vmwareSetSentinal(cmd, NOGUI); + else + vmwareSetSentinal(cmd, NULL); + + if (virRun(cmd, NULL) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VMRUN); + goto cleanup; + } + + virStrToLong_i(vm->def->name, NULL, 10, &vm->pid); + vm->def->id = vm->pid; + vm->state = VIR_DOMAIN_RUNNING; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static char * +formatVMXFileName(const char *datastorePath, void *opaque) +{ + (void)opaque; + char *path = NULL; + int len = strlen(datastorePath); + + if (VIR_ALLOC_N(path, len) < 0) { + virReportOOMError(); + return NULL; + } + + if (virStrcpy(path, datastorePath, len) == NULL) { + VIR_FREE(path); + return NULL; + } + + return path; +} + +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; + + pvmwareDomain pDomain = NULL; + + esxVMX_Context ctx; + + ctx.formatFileName = formatVMXFileName; + + vmwareDriverLock(driver); + if ((vmdef = virDomainDefParseString(driver->caps, xml, + VIR_DOMAIN_XML_INACTIVE)) == NULL) + goto cleanup; + + vm = virDomainFindByName(&driver->domains, vmdef->name); + if (vm) { + vmwareError(VIR_ERR_OPERATION_FAILED, + _("Already an VMWARE VM active with the id '%s'"), + vmdef->name); + goto cleanup; + } + + /* genrerate vmx file + * TODO : add vmware specific ProductVersion + */ + vmx = esxVMX_FormatConfig(&ctx, driver->caps, vmdef, + esxVI_ProductVersion_ESX4x); + if (vmx == NULL) { + vmwareError(VIR_ERR_OPERATION_FAILED, "cannot create xml "); + goto cleanup; + } + + if (vmwareVmxPath(vmdef, &vmxPath) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("retrieve vmx path.. failed")); + goto cleanup; + } + + /* create vmx file */ + int fd; + + if ((fd = + open(vmxPath, O_CREAT | O_WRONLY | O_TRUNC, + S_IRUSR | S_IWUSR)) == -1) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open/create vmx file '%s'"), vmxPath); + goto cleanup; + } + if (safewrite(fd, vmx, strlen(vmx)) < 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; + + //* save vmxpath in domain object * // + if (VIR_ALLOC(pDomain) < 0) { + virReportOOMError(); + goto cleanup; + } + pDomain->vmxPath = strdup(vmxPath); + vm->privateData = (void *) pDomain; + vm->privateDataFreeFunc = vmwareDataFreeFunc; + + 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; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "stop", + PROGRAM_SENTINAL, "soft", NULL + }; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_INVALID_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((pvmwareDomain) 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->def->id = -1; + vm->state = VIR_DOMAIN_SHUTOFF; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +vmwareDomainDestroy(virDomainPtr dom) +{ + struct vmware_driver *driver = dom->conn->privateData; + + virDomainObjPtr vm; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, "stop", + PROGRAM_SENTINAL, "hard", NULL + }; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_INVALID_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((pvmwareDomain) vm->privateData)->vmxPath); + if (vm->state == VIR_DOMAIN_RUNNING) { + } + if (virRun(cmd, NULL) < 0) + goto cleanup; + vm->def->id = -1; + vm->state = VIR_DOMAIN_SHUTOFF; + + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + + ret = 0; + cleanup: + if (vm) + virDomainObjUnlock(vm); + 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_INVALID_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((pvmwareDomain) 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->def->id = -1; + 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_INVALID_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((pvmwareDomain) 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->def->id = -1; + 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; + + virDomainObjPtr vm; + const char *cmd[] = { + VMRUN, "-T", PROGRAM_SENTINAL, + "reset", PROGRAM_SENTINAL, NULL + }; + int ret = -1; + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_INVALID_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + vmwareSetSentinal(cmd, vmw_types[driver->type]); + vmwareSetSentinal(cmd, ((pvmwareDomain) 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->def->id = -1; + vm->state = VIR_DOMAIN_RUNNING; + ret = 0; + + cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +vmwareDomainSave(virDomainPtr dom, const char *path) +{ + struct vmware_driver *driver = dom->conn->privateData; + + virDomainObjPtr vm; + const char *cmdsuspend[] = { + VMRUN, "-T", PROGRAM_SENTINAL, + "suspend", PROGRAM_SENTINAL, NULL + }; + int ret = -1; + + char *fDirectoryName = NULL; + + char *fFileName = NULL; + + char *tDirectoryName = NULL; + + char *tFileName = NULL; + + char *copyPath = NULL; + + char *copyvmxPath = NULL; + + char *fvmss = NULL; + + char *tvmss = NULL; + + char *fvmem = NULL; + + char *tvmem = NULL; + + char *fvmx = NULL; + + char *tvmx = NULL; + + + vmwareDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + vmwareDriverUnlock(driver); + + if (!vm) { + vmwareError(VIR_ERR_INVALID_DOMAIN, "%s", + _("no domain with matching uuid")); + goto cleanup; + } + + /* vmware suspend */ + vmwareSetSentinal(cmdsuspend, vmw_types[driver->type]); + vmwareSetSentinal(cmdsuspend, + ((pvmwareDomain) 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(cmdsuspend, NULL) < 0) + goto cleanup; + + /* create files path */ + copyvmxPath = strdup(((pvmwareDomain) vm->privateData)->vmxPath); + copyPath = strdup(path); + + if (vmwareParsePath(copyvmxPath, &fDirectoryName, &fFileName) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse vmxPath")); + goto cleanup; + } + if (vmwareParsePath(copyPath, &tDirectoryName, &tFileName) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse path")); + goto cleanup; + } + + /* dir */ + if (virFileMakePath(tDirectoryName) != 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", _("make path error")); + goto cleanup; + } + + vmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmss", &fvmss); + vmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmss", &tvmss); + vmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmem", &fvmem); + vmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmem", &tvmem); + vmwareMakePath(fDirectoryName, vm->def->name, (char *) "vmx", &fvmx); + vmwareMakePath(tDirectoryName, vm->def->name, (char *) "vmx", &tvmx); + + /* create linker file */ + int fd; + + if ((fd = + open(path, O_CREAT | O_WRONLY | O_TRUNC, + S_IRUSR | S_IWUSR)) == -1) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open linker file '%s'"), path); + goto cleanup; + } + if (safewrite + (fd, ((pvmwareDomain) vm->privateData)->vmxPath, + strlen(((pvmwareDomain) vm->privateData)->vmxPath)) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to create linker file")); + goto cleanup; + } + + if (STREQ(fDirectoryName, tDirectoryName)) { // we want to let saved VM inside default directory + printf("default dir - no move\n"); + goto end; + } + + /* move {vmx,vmss,vmem} files */ + if ((vmwareMoveFile(fvmss, tvmss) < 0) + || (vmwareMoveFile(fvmem, tvmem) < 0) + || (vmwareMoveFile(fvmx, tvmx) < 0) + ) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to move file")); + goto cleanup; + } + + end: + vm->def->id = -1; + vm->state = VIR_DOMAIN_SHUTOFF; + ret = 0; + + cleanup: + VIR_FREE(fDirectoryName); + VIR_FREE(fFileName); + VIR_FREE(tDirectoryName); + VIR_FREE(tFileName); + VIR_FREE(copyPath); + VIR_FREE(copyvmxPath); + + VIR_FREE(fvmss); + VIR_FREE(tvmss); + VIR_FREE(fvmem); + VIR_FREE(tvmem); + VIR_FREE(fvmx); + VIR_FREE(tvmx); + if (vm) + virDomainObjUnlock(vm); + return ret; +} + +static int +vmwareDomainRestore(virConnectPtr conn, const char *path) +{ + struct vmware_driver *driver = conn->privateData; + + virDomainDefPtr vmdef = NULL; + + virDomainPtr dom = NULL; + + int ret = -1; + + char *vmxPath = NULL; + + char *copypath = NULL; + + char *copyvmxPath = NULL; + + char *tDirectoryName = NULL; + + char *tFileName = NULL; + + char *fDirectoryName = NULL; + + char *fFileName = NULL; + + char *vmx = NULL; + + char *xml = NULL; + + char *sep = NULL; + + char *baseVmss; + + char *fvmss = NULL; + + char *tvmss = NULL; + + char *fvmem = NULL; + + char *tvmem = NULL; + + char *fvmx = NULL; + + char *tvmx = NULL; + + if (!virFileExists(path)) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("file %s does not exist"), path); + goto cleanup; + } + if (virFileHasSuffix(path, ".vmx")) { //we want to restore a vm saved in its default directory + tvmx = strdup(path); + copypath = strdup(path); + if (vmwareParsePath(copypath, &fDirectoryName, &fFileName) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse path")); + goto cleanup; + } + sep = strrchr(fFileName, '.'); + if (sep != NULL) + *sep = '\0'; + vmwareMakePath(fFileName, fFileName, (char *) "vmss", &fvmss); + baseVmss = basename(fvmss); + } else { //we want to restore a vm saved elsewhere + if (virFileReadAll(path, 1024, &vmxPath) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to read vmxPath")); + goto cleanup; + } + //printf("vmxPath ---> %s \n",vmxPath); + if (!virFileHasSuffix(vmxPath, ".vmx")) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("%s is not a .vmx file"), vmxPath); + goto cleanup; + } + + /* move files */ + copyvmxPath = strdup(vmxPath); + copypath = strdup(path); + + if (vmwareParsePath(copypath, &fDirectoryName, &fFileName) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse path")); + goto cleanup; + } + if (vmwareParsePath(copyvmxPath, &tDirectoryName, &tFileName) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse vmxPath")); + goto cleanup; + } + + sep = strrchr(tFileName, '.'); + if (sep != NULL) + *sep = '\0'; + //printf("fFileName ---> %s \n",fFileName); + //printf("fDirectoryName ---> %s \n",fDirectoryName); + //printf("tDirectoryName ---> %s \n",tDirectoryName); + + if (virFileMakePath(tDirectoryName) != 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("make path error")); + goto cleanup; + } + + vmwareMakePath(fDirectoryName, tFileName, (char *) "vmss", &fvmss); + vmwareMakePath(tDirectoryName, tFileName, (char *) "vmss", &tvmss); + vmwareMakePath(fDirectoryName, tFileName, (char *) "vmem", &fvmem); + vmwareMakePath(tDirectoryName, tFileName, (char *) "vmem", &tvmem); + vmwareMakePath(fDirectoryName, tFileName, (char *) "vmx", &fvmx); + vmwareMakePath(tDirectoryName, tFileName, (char *) "vmx", &tvmx); + + if ((vmwareMoveFile(fvmss, tvmss) < 0) + || (vmwareMoveFile(fvmem, tvmem) < 0) + || (vmwareMoveFile(fvmx, tvmx) < 0) + ) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to move files")); + goto cleanup; + } + + baseVmss = basename(tvmss); + } + + //printf("reading vmx file... %s \n", tvmx); + if (virFileReadAll(tvmx, 10000, &vmx) == -1) { + perror("error reading vmx file"); + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("failed to read vmx file %s"), tvmx); + goto cleanup; + } + + if ((vmdef = + esxVMX_ParseConfig(NULL, driver->caps, vmx, + esxVI_ProductVersion_ESX4x)) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse config file")); + goto cleanup; + } + + xml = virDomainDefFormat(vmdef, VIR_DOMAIN_XML_SECURE); + + if ((dom = vmwareDomainDefineXML(conn, xml)) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to define domain")); + printf("xml -->>> %s \n", xml); + goto cleanup; + } + + /* esxVMX_ParseConfig don't care about vmx checkpoint property for now, so we add it here + * TODO + */ + FILE *pFile = NULL; + + if ((pFile = fopen(tvmx, "a+")) == NULL) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to reopen vmx file")); + goto cleanup; + } + //printf("adding checkpoint.vmState = \"%s\"\n",tvmss); + fputs("checkpoint.vmState = \"", pFile); + fputs(baseVmss, pFile); + fputs("\"", pFile); + fclose(pFile); + + /* start */ + if (vmwareDomainCreate(dom) < 0) { + vmwareError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to create domain")); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(vmxPath); + VIR_FREE(copypath); + VIR_FREE(copyvmxPath); + VIR_FREE(tDirectoryName); + VIR_FREE(tFileName); + VIR_FREE(fDirectoryName); + VIR_FREE(fFileName); + VIR_FREE(vmx); + VIR_FREE(xml); + + VIR_FREE(fvmss); + VIR_FREE(tvmss); + VIR_FREE(fvmem); + VIR_FREE(tvmem); + VIR_FREE(fvmx); + VIR_FREE(tvmx); + + if (dom) + virUnrefDomain(dom); + return ret; +} + +static virDomainPtr +vmwareDomainCreateXML(virConnectPtr conn, const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + + dom = vmwareDomainDefineXML(conn, xml); + if (dom == NULL) + return NULL; + + if (vmwareDomainCreate(dom) < 0) { + virUnrefDomain(dom); + return NULL; + } + + return dom; +} + +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 delete active domain")); + goto cleanup; + } + + if (!vm->persistent) { + vmwareError(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot undefine transient domain")); + goto cleanup; + } + + if (vm->privateDataFreeFunc) + vm->privateDataFreeFunc(vm->privateData); + + 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_INVALID_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_INVALID_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 */ + vmwareDomainDestroy, /* domainDestroy */ + vmwareGetOSType, /* domainGetOSType */ + NULL, /* domainGetMaxMemory */ + NULL, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + vmwareDomainGetInfo, /* domainGetInfo */ + vmwareDomainSave, /* domainSave */ + vmwareDomainRestore, /* 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 */ + NULL, /* 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, /* 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 0000000..0996777 --- /dev/null +++ b/src/vmware/vmware_driver.h @@ -0,0 +1,27 @@ +/*---------------------------------------------------------------------------*/ +/* 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 + +# include "internal.h" + +int vmwareRegister(void); + +#endif -- 1.7.0.4
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list