[libvirt] [PATCH 1/4] Addition of XenAPI support to libvirt

Resending patches in plain text. ~/Libvirt/Src/Makefile.am contains some changes suggested by Daniel Veillard. This is a patch to add XenAPI driver support for libvirt version 0.7.6. XenAPI can be used against XenCloud platform and managed through virsh and virt-manger. This patch supports domain related APIs in libvirt. It is possible to get domain information, list active and inactive domains, get Domain XML configuration and Start/stop/pause/shutdown/destroy VMs. There will be more patches after this review to support more libvirt APIs and add remote storage support to XenAPI. In order to run this patch you would require libxenserver library. Libxenserver library can be downloaded from http://community.citrix.com/download/attachments/38633496/libxenserver-5.5.0... Copy the libxenserver folder in the same directory level as libvirt. The XenCloud platform can be downloaded from http://xen.org/products/cloudxen.html diff -ur ./libvirt_org/configure.ac ./libvirt/configure.ac --- ./libvirt_org/configure.ac 2010-02-17 17:39:21.000000000 +0000 +++ ./libvirt/configure.ac 2010-02-18 11:51:29.000000000 +0000 @@ -219,6 +219,8 @@ AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes]) AC_ARG_WITH([phyp], AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check]) +AC_ARG_WITH([xenapi], + AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=yes@:>@]),[],[with_xenapi=check]) AC_ARG_WITH([vbox], AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes]) AC_ARG_WITH([lxc], @@ -307,6 +309,11 @@ fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"]) +if test "$with_xenapi" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi +AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) + if test "$with_libvirtd" = "no" ; then with_qemu=no fi @@ -1894,6 +1901,7 @@ AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ PHYP: $with_phyp]) AC_MSG_NOTICE([ ONE: $with_one]) Binary files ./libvirt_org/daemon/.libs/libvirtd and ./libvirt/daemon/.libs/libvirtd differ Only in ./libvirt_org/daemon/.libs: lt-libvirtd --- ./libvirt_org/src/Makefile.am 2010-02-17 17:38:13.000000000 +0000 +++ ./libvirt/src/Makefile.am 2010-02-19 10:55:51.000000000 +0000 @@ -3,12 +3,19 @@ # No libraries with the exception of LIBXML should be listed # here. List them against the individual XXX_la_CFLAGS targets # that actually use them + +XENAPI_CFLAGS = -I@top_srcdir@/../libxenserver/include + INCLUDES = \ -I$(top_srcdir)/gnulib/lib \ -I../gnulib/lib \ -I../include \ + -I/usr/include \ -I@top_srcdir@/src/util \ + -I@top_srcdir@/src \ + -I@top_srcdir@/src/xenapi \ -I@top_srcdir@/include \ + $(XENAPI_CFLAGS) \ $(DRIVER_MODULE_CFLAGS) \ $(LIBXML_CFLAGS) \ -DLIBDIR=\""$(libdir)"\" \ @@ -42,6 +49,9 @@ augeastestdir = $(datadir)/augeas/lenses/tests augeastest_DATA = +XENAPI_LIBS = @top_srcdir@/../libxenserver/libxenserver.so +XENAPI_LDFLAGS = -L@top_srcdir@/../libxenserver/ -lxenserver + # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ @@ -205,6 +215,10 @@ qemu/qemu_security_dac.h \ qemu/qemu_security_dac.c +XENAPI_DRIVER_SOURCES = \ + xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ + xenapi/xenapi_utils.c xenapi/xenapi_utils.h + UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ uml/uml_driver.c uml/uml_driver.h @@ -466,6 +480,28 @@ libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES) endif +if WITH_XENAPI +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xenapi.la +else +noinst_LTLIBRARIES += libvirt_driver_xenapi.la + +libvirt_la_LIBADD += libvirt_driver_xenapi.la \ + $(XENAPI_LIBS) +endif +#libvirt_driver_xenapi_la_LIBADD = $(XENAPI_LIBS) +libvirt_driver_xenapi_la_CFLAGS = $(XEN_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(shell curl-config --cflags) +libvirt_driver_xenapi_la_LDFLAGS = $(XENAPI_LDFLAGS) -g $(LIBXML_LIBS) \ + $(shell curl-config --libs) + +if WITH_DRIVER_MODULES +libvirt_driver_xenapi_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES) +endif + if WITH_QEMU if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_qemu.la @@ -722,6 +758,7 @@ $(OPENVZ_DRIVER_SOURCES) \ $(PHYP_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ + $(XENAPI_DRIVER_SOURCES) \ $(ESX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ diff -ur ./libvirt_org/tools/Makefile.am ./libvirt/tools/Makefile.am --- ./libvirt_org/tools/Makefile.am 2010-02-17 17:36:13.000000000 +0000 +++ ./libvirt/tools/Makefile.am 2010-02-18 11:56:30.000000000 +0000 @@ -40,7 +40,8 @@ $(WARN_CFLAGS) \ ../src/libvirt.la \ ../gnulib/lib/libgnu.la \ - $(VIRSH_LIBS) + $(VIRSH_LIBS) \ + ../../libxenserver/libxenserver.so virsh_CFLAGS = \ -I$(top_srcdir)/gnulib/lib -I../gnulib/lib \ -I../include -I$(top_srcdir)/include \

diff -ur ./libvirt_org/src/libvirt.c ./libvirt/src/libvirt.c --- ./libvirt_org/src/libvirt.c 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/libvirt.c 2010-02-18 12:21:43.000000000 +0000 @@ -64,6 +64,9 @@ #ifdef WITH_ESX #include "esx/esx_driver.h" #endif +#ifdef WITH_XENAPI +#include "xenapi/xenapi_driver.h" +#endif #endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -357,6 +360,7 @@ virDriverLoadModule("openvz"); virDriverLoadModule("vbox"); virDriverLoadModule("esx"); + virDriverLoadModule("xenapi"); virDriverLoadModule("remote"); #else #ifdef WITH_TEST @@ -377,6 +381,9 @@ #ifdef WITH_ESX if (esxRegister() == -1) return -1; #endif +#ifdef WITH_XENAPI + if (xenapiRegister () == -1) return -1; +#endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -1035,6 +1042,10 @@ if (STRCASEEQ(type, "Remote")) *typeVer = remoteVersion(); #endif +#if WITH_XENAPI + if (STRCASEEQ(type, "XenAPI")) + *typeVer = LIBVIR_VERSION_NUMBER; +#endif if (*typeVer == 0) { virLibConnError(NULL, VIR_ERR_NO_SUPPORT, type); goto error; diff -ur ./libvirt_org/src/driver.h ./libvirt/src/driver.h --- ./libvirt_org/src/driver.h 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/driver.h 2010-02-18 10:45:54.000000000 +0000 @@ -27,6 +27,7 @@ VIR_DRV_ONE = 9, VIR_DRV_ESX = 10, VIR_DRV_PHYP = 11, + VIR_DRV_XENAPI = 12 } virDrvNo; diff -ur ./libvirt_org/include/libvirt/virterror.h ./libvirt/include/libvirt/virterror.h --- ./libvirt_org/include/libvirt/virterror.h 2010-02-17 17:37:51.000000000 +0000 +++ ./libvirt/include/libvirt/virterror.h 2010-02-18 12:17:54.000000000 +0000 @@ -69,6 +69,7 @@ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ VIR_FROM_SECRET, /* Error from secret storage */ VIR_FROM_CPU, /* Error from CPU driver */ + VIR_FROM_XENAPI /* Error from XenAPI */ } virErrorDomain; diff -ur ./libvirt_org/src/util/virterror.c ./libvirt/src/util/virterror.c --- ./libvirt_org/src/util/virterror.c 2010-02-17 17:38:14.000000000 +0000 +++ ./libvirt/src/util/virterror.c 2010-02-18 12:13:08.000000000 +0000 @@ -85,6 +85,9 @@ case VIR_FROM_XEN: dom = "Xen "; break; + case VIR_FROM_XENAPI: + dom = "XenAPI "; + break; case VIR_FROM_XML: dom = "XML "; break; Only in ./libvirt/src: xenapi

On Fri, Feb 19, 2010 at 11:21:10AM +0000, Sharadha Prabhakar (3P) wrote:
diff -ur ./libvirt_org/src/libvirt.c ./libvirt/src/libvirt.c --- ./libvirt_org/src/libvirt.c 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/libvirt.c 2010-02-18 12:21:43.000000000 +0000 @@ -64,6 +64,9 @@ #ifdef WITH_ESX #include "esx/esx_driver.h" #endif +#ifdef WITH_XENAPI +#include "xenapi/xenapi_driver.h" +#endif #endif
#define VIR_FROM_THIS VIR_FROM_NONE @@ -357,6 +360,7 @@ virDriverLoadModule("openvz"); virDriverLoadModule("vbox"); virDriverLoadModule("esx"); + virDriverLoadModule("xenapi"); virDriverLoadModule("remote"); #else #ifdef WITH_TEST @@ -377,6 +381,9 @@ #ifdef WITH_ESX if (esxRegister() == -1) return -1; #endif +#ifdef WITH_XENAPI + if (xenapiRegister () == -1) return -1; +#endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -1035,6 +1042,10 @@ if (STRCASEEQ(type, "Remote")) *typeVer = remoteVersion(); #endif +#if WITH_XENAPI + if (STRCASEEQ(type, "XenAPI")) + *typeVer = LIBVIR_VERSION_NUMBER; +#endif if (*typeVer == 0) { virLibConnError(NULL, VIR_ERR_NO_SUPPORT, type); goto error;
diff -ur ./libvirt_org/src/driver.h ./libvirt/src/driver.h --- ./libvirt_org/src/driver.h 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/driver.h 2010-02-18 10:45:54.000000000 +0000 @@ -27,6 +27,7 @@ VIR_DRV_ONE = 9, VIR_DRV_ESX = 10, VIR_DRV_PHYP = 11, + VIR_DRV_XENAPI = 12 } virDrvNo;
diff -ur ./libvirt_org/include/libvirt/virterror.h ./libvirt/include/libvirt/virterror.h --- ./libvirt_org/include/libvirt/virterror.h 2010-02-17 17:37:51.000000000 +0000 +++ ./libvirt/include/libvirt/virterror.h 2010-02-18 12:17:54.000000000 +0000 @@ -69,6 +69,7 @@ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ VIR_FROM_SECRET, /* Error from secret storage */ VIR_FROM_CPU, /* Error from CPU driver */ + VIR_FROM_XENAPI /* Error from XenAPI */ } virErrorDomain;
diff -ur ./libvirt_org/src/util/virterror.c ./libvirt/src/util/virterror.c --- ./libvirt_org/src/util/virterror.c 2010-02-17 17:38:14.000000000 +0000 +++ ./libvirt/src/util/virterror.c 2010-02-18 12:13:08.000000000 +0000 @@ -85,6 +85,9 @@ case VIR_FROM_XEN: dom = "Xen "; break; + case VIR_FROM_XENAPI: + dom = "XenAPI "; + break; case VIR_FROM_XML: dom = "XML "; break;
All straightforward & looks fine Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-18 16:26:13.000000000 +0000 @@ -0,0 +1,1774 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password( call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + privP = malloc(sizeof(struct _xenapiPrivate)); + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + *hvVer = 1; + return 0; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +} + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + createVMRecordFromXml( conn, xmlDesc, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup(result->contents[i].val); + } else { + os_version = strdup("linux"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + virBufferAddLit(&buf, "<domain type='xenapi'>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", "testVM"); + virUUIDFormat(dom->uuid,uuid_string); + virBufferEscapeString(&buf, " <uuid>%s</uuid>\n",uuid_string); + + + virBufferAddLit(&buf, " <os>\n"); + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + virBufferAddLit(&buf, " <type>hvm</type>\n"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int j=0; + while(result->contents[i].val[j]!='\0') { + virBufferEscapeString(&buf, " <boot dev='%s' />\n", + mapXmlBootOrder(result->contents[i].val[j])); + j++; + } + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + virBufferAddLit(&buf, " <type>linux</type>\n"); + virBufferAddLit(&buf, " <loader>pygrub</loader>\n"); + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <kernel>%s</kernel>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <initrd>%s</initrd>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <cmdline>%s</cmdline>\n",value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + } + virBufferAddLit(&buf, " </os>\n"); + virBufferAddLit(&buf, " <bootloader>pygrub</bootloader>\n"); + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + virBufferEscapeString(&buf," <bootloader_args>%s</bootloader_args>\n",val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + virBufferVSprintf(&buf," <memory>%lu</memory>\n",memory); + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + virBufferVSprintf(&buf," <currentmemory>%lld</currentmemory>\n",(dynamic_mem/1024)); + } else { + virBufferVSprintf(&buf," <currentmemory>%lu</currentmemory>\n",memory); + } + virBufferVSprintf(&buf," <vcpu>%d</vcpu>\n",xenapiDomainGetMaxVcpus(dom)); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_poweroff>%s</on_poweroff>\n",xen_on_normal_exit_to_string(action)); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_reboot>%s</on_reboot>\n",xen_on_normal_exit_to_string(action)); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + virBufferEscapeString(&buf," <on_crash>%s</on_crash>\n",xen_on_crash_behaviour_to_string(crash)); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + virBufferAddLit(&buf, " <features>\n"); + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + virBufferVSprintf(&buf," <%s/>\n",result->contents[i].key); + } + } + virBufferAddLit(&buf, " </features>\n"); + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + for (i=0; i<vif_set->size; i++) { + virBufferAddLit(&buf, " <interface type='bridge'>\n"); + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + virBufferEscapeString(&buf," <source bridge='%s' />\n",bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + xen_vif_record_free(vif_rec); + } + virBufferAddLit(&buf, " </interface>\n"); + } + xen_vif_set_free(vif_set); + } + virBufferAddLit(&buf, "</domain>"); + if (vms) xen_vm_set_free(vms); + return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + if(createVMRecordFromXml( conn, xml, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-18 15:37:49.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * xenapi.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> + +//#define PRINT_XML +#define RAW_UUID_BUFLEN (16) +#define LIBVIRT_MODELNAME_LEN (32) + + +extern int xenapiRegister (void); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; + xen_api_version version; +}; + +#endif /* __VIR_XENAPI_H__ */

On Fri, Feb 19, 2010 at 11:23:32AM +0000, Sharadha Prabhakar (3P) wrote:
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-18 16:26:13.000000000 +0000 @@ -0,0 +1,1774 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + }
The xenapiSessionErrorHandler function should really be declared as a macro that automatically adds FILE/FUNCTION/LINE, rather than requiring all callers todo this. For example, the QEMU driver defines a simple macro for error reporting that looks like this: #define qemuReportError(code, fmt...) \ virReportErrorHelper(NULL, VIR_FROM_QEMU, code, __FILE__, \ __FUNCTION__, __LINE__, fmt) Also, as of last week, we no longer recommend passing 'conn' into error handlers. We've not updated all existing code to follow this scheme, but you can just leave it out of your new code.
+ if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims);
Don't encode the password in the URI, since this is very insecure - the URIs get logged everywhere. The 'virConnectAuthPtr auth' parameter passed to this method provides a way for your driver to prompt for a password. If you want a simple example of how to use this parameter for collecting a password have a look at the esxUtil_RequestPassword() method in the src/esx/esx_util.c method - I expect it does exactly what you will need.
+ url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0';
The libvirt coding standards don't allow the use of malloc(), realloc() or free() since this APIs are very error-prone. Take a look at the HACKING file for the 'Low level memory management' section which describes our replacements VIR_ALLOC/REALLOC/FREE. In this particular case though, since you're building up a string, just call virAsprintf(), eg virAsprintf(&url, "https://"%s/", conn->uri->sever)
+ + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password( call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + privP = malloc(sizeof(struct _xenapiPrivate));
Same note about malloc() as above - in this case you'll want VIR_ALLOC(privP)
+ privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + *hvVer = 1;
This should really be the Xen hypervisor version
+ return 0;
And this should return the XenAPI library version
+} +
+/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +}
These days, we don't let the drivers format or parse any XML directly. Instead there are standard APIs that drivers can call out to, which are all under the src/conf/ directory. In this case you'll want the capabilities.h file, which lets you construct a virCapsPtr object. Once populatd, you can serialize it to XML format using virCapabilitiesFormatXML(). Also, the domain type should be 'xen' rather than 'xenapi', since this refers to the hypervisor type, not the API type.
+ +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]);
Rather than repeatedly casting conn->privateData at every usage, the common style in libvirt drivers is to declare it as the first variable at entry to the function, eg struct _xenapiPrivate *priv = conn->privateData; then just refer to priv->session where needed during the function/
+ ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} +
+ +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + createVMRecordFromXml( conn, xmlDesc, &record, &vm);
As with the capabilities API, we have standard API for parsing the domain XML format too. So this code would just do something like virDomainDefPtr def = virDomainDefParseString(caps, xmlDesc, flags); then pass 'def' into your createVMRecordFromXml() method instead of the raw XML file.
+ if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid);
Once you've using the 'virDomainDefPtr' object you'll not need this since you can just directly use def->uuid which is already in raw format.
+ if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + + + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup(result->contents[i].val); + } else { + os_version = strdup("linux"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +}
This libvirt method / API actually has a rather misleading name. It is not wanting the guest operating system name, but rather the guest ABI. Which in case of Xen is either 'xen' (paravirt) or 'hvm' (fullvirt).
+ +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +}
For any method not supported by XenAPI, simply leave it out of your driver altogether - put a NULL in the virDriver struct entry at the end of your file. libvirt will then automatically report a VIR_ERR_NO_SUPPORT error.
+ +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED)
The 'to' parameter shouldn't be unused here. The guest state should be saved to this named file. If XenAPI doesn't support saving to an explicit named file, then just leave out this libvirt driver API. In the future we will add a new save/restore API that doesn't require a named file.
+{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED)
Same comment here as with save - it must restore state from this named file. Otherwise leave out this method.
+{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + virBufferAddLit(&buf, "<domain type='xenapi'>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", "testVM"); + virUUIDFormat(dom->uuid,uuid_string); + virBufferEscapeString(&buf, " <uuid>%s</uuid>\n",uuid_string);
As mentioned earlier, this method shouldn't be writing out XML directly. What you want todo is build a virDomainDefPtr object with all the data. Then just call virDomainDefFormat() to generate the XML document.
+ + + virBufferAddLit(&buf, " <os>\n"); + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + virBufferAddLit(&buf, " <type>hvm</type>\n"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int j=0; + while(result->contents[i].val[j]!='\0') { + virBufferEscapeString(&buf, " <boot dev='%s' />\n", + mapXmlBootOrder(result->contents[i].val[j])); + j++; + } + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + virBufferAddLit(&buf, " <type>linux</type>\n"); + virBufferAddLit(&buf, " <loader>pygrub</loader>\n"); + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <kernel>%s</kernel>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <initrd>%s</initrd>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <cmdline>%s</cmdline>\n",value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + } + virBufferAddLit(&buf, " </os>\n"); + virBufferAddLit(&buf, " <bootloader>pygrub</bootloader>\n"); + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + virBufferEscapeString(&buf," <bootloader_args>%s</bootloader_args>\n",val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + virBufferVSprintf(&buf," <memory>%lu</memory>\n",memory); + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + virBufferVSprintf(&buf," <currentmemory>%lld</currentmemory>\n",(dynamic_mem/1024)); + } else { + virBufferVSprintf(&buf," <currentmemory>%lu</currentmemory>\n",memory); + } + virBufferVSprintf(&buf," <vcpu>%d</vcpu>\n",xenapiDomainGetMaxVcpus(dom)); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_poweroff>%s</on_poweroff>\n",xen_on_normal_exit_to_string(action)); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_reboot>%s</on_reboot>\n",xen_on_normal_exit_to_string(action)); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + virBufferEscapeString(&buf," <on_crash>%s</on_crash>\n",xen_on_crash_behaviour_to_string(crash)); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + virBufferAddLit(&buf, " <features>\n"); + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + virBufferVSprintf(&buf," <%s/>\n",result->contents[i].key); + } + } + virBufferAddLit(&buf, " </features>\n"); + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + for (i=0; i<vif_set->size; i++) { + virBufferAddLit(&buf, " <interface type='bridge'>\n"); + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + virBufferEscapeString(&buf," <source bridge='%s' />\n",bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + xen_vif_record_free(vif_rec); + } + virBufferAddLit(&buf, " </interface>\n"); + } + xen_vif_set_free(vif_set); + } + virBufferAddLit(&buf, "</domain>"); + if (vms) xen_vm_set_free(vms); + return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +}
Just leave these out & libvirt automatically report VIR_ERR_NO_SUPPORT
+ +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
You shouldn't disable SSL verification here. It should be on by default. For consistency with other libvirt drivers, you may wish to allow your xenapi:/// uri to have an optional 'no_verify=1' parameter to turn off SSL verification. It should always be verifying by default though.
+ CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-18 15:37:49.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * xenapi.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> + +//#define PRINT_XML +#define RAW_UUID_BUFLEN (16)
This one already exists as VIR_UUID_BUFLEN
+#define LIBVIRT_MODELNAME_LEN (32) + + +extern int xenapiRegister (void); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms);
I think those two can be left out & just declared static in the source file, since they're not used externally.
+ +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; + xen_api_version version; +}; + +#endif /* __VIR_XENAPI_H__ */
Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

Hi Daniel, I've submitted my XenAPI driver in 2parts before sometime with all the changes you had suggested. The following is possibly the only one that's not handled.
+ curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
You shouldn't disable SSL verification here. It should be on by default. For consistency with other libvirt drivers, you may wish to allow your xenapi:/// uri to have an optional 'no_verify=1' parameter to turn off SSL verification. It should always be verifying by default though.
For now I have enabled verify SSL. I'm not sure about how libvirt hands Over the no_verify=1 part that the user types in the URI to my driver. virDrvOpen only receives the URI elements from 'conn' parameter. I couldn't find this information embedded in 'conn'? Could you explain how to get this information? Regards, Sharadha

2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Hi Daniel, I've submitted my XenAPI driver in 2parts before sometime with all the changes you had suggested. The following is possibly the only one that's not handled.
+ curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
You shouldn't disable SSL verification here. It should be on by default. For consistency with other libvirt drivers, you may wish to allow your xenapi:/// uri to have an optional 'no_verify=1' parameter to turn off SSL verification. It should always be verifying by default though.
For now I have enabled verify SSL. I'm not sure about how libvirt hands Over the no_verify=1 part that the user types in the URI to my driver. virDrvOpen only receives the URI elements from 'conn' parameter. I couldn't find this information embedded in 'conn'? Could you explain how to get this information? Regards, Sharadha
See esxOpen and esxUtil_ParseQuery for an example how the ESX driver implements this. Matthias

diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-18 16:26:52.000000000 +0000 @@ -0,0 +1,507 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +/* returns 'file' or 'block' for the storage type */ +int +getStorageVolumeType(char *type) +{ + if((STREQ(type,"lvmoiscsi")) || + (STREQ(type,"lvmohba")) || + (STREQ(type,"lvm")) || + (STREQ(type,"file")) || + (STREQ(type,"iso")) || + (STREQ(type,"ext")) || + (STREQ(type,"nfs"))) + return (int)VIR_STORAGE_VOL_FILE; + else if((STREQ(type,"iscsi")) || + (STREQ(type,"equal")) || + (STREQ(type,"hba")) || + (STREQ(type,"cslg")) || + (STREQ(type,"udev")) || + (STREQ(type,"netapp"))) + return (int)VIR_STORAGE_VOL_BLOCK; + return -1; +} + +/* returns error description if any received from the server */ +char * +returnErrorFromSession(xen_session *session) +{ + int i; + char *buf = NULL; + for (i=0; i<session->error_description_count-1; i++) { + if (buf==NULL) { + buf = (char *)realloc(buf,strlen(session->error_description[i])+1); + strcpy(buf,session->error_description[i]); + } else { + buf = (char *)realloc(buf,strlen(buf)+strlen(session->error_description[i])+2); + strcat(buf,":"); + strcat(buf,session->error_description[i]); + } + } + return buf; +} + +/* XenAPI error handler - internally calls libvirt error handler after clearing error +flag in session */ +void xenapiSessionErrorHandler(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} + +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf); + } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr); + return ret; +} + +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL; + bzero(cpumap, maplen); + num = strtok (mask, ","); + while (num != NULL) { + sscanf (num, "%d", &pos); + if (pos<0 || pos>max_bits-1) + printf ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok (NULL, ","); + } +} + + +/* mapping XenServer power state to Libvirt power state */ +virDomainState +mapPowerState(enum xen_vm_power_state state) +{ + virDomainState virState; + switch (state) { + case (XEN_VM_POWER_STATE_HALTED): + case (XEN_VM_POWER_STATE_SUSPENDED): + virState = VIR_DOMAIN_SHUTOFF; + break; + case (XEN_VM_POWER_STATE_PAUSED): + virState = VIR_DOMAIN_PAUSED; + break; + case (XEN_VM_POWER_STATE_RUNNING): + virState = VIR_DOMAIN_RUNNING; + break; + case (XEN_VM_POWER_STATE_UNKNOWN): + case (XEN_VM_POWER_STATE_UNDEFINED): + virState = VIR_DOMAIN_NOSTATE; + break; + default: + virState = VIR_DOMAIN_NOSTATE; + break; + } + return virState; +} + +/* Gets the value of the child for the current node passed */ +char * +getXmlChildValue(xmlDocPtr doc, xmlNodePtr cur, const char *tag) +{ + char *key = NULL; + cur = cur->xmlChildrenNode; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)tag))){ + cur = cur->xmlChildrenNode; + key = (char *)xmlNodeListGetString(doc,cur,1); + } + cur = cur->next; + } + return key; +} + +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + *strings = realloc(*strings,sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz); + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val); + return 0; +} + +/* create boot order string as understood by libvirt */ +void +createXmlBootOrderString(char **order, char *key) +{ + int sz = ((*order)==NULL)?0:(strlen(*order)+1); + const char *temp=NULL; + if (strcmp(key,"fd")==0) + temp="a"; + else if (strcmp(key,"hd")==0) + temp="c"; + else if (strcmp(key,"cdrom")==0) + temp="d"; + else if (strcmp(key,"network")==0) + temp="n"; + if (temp!=NULL) { + *order = (char *)realloc(*order,sz+strlen(temp)+1); + if(sz==0) strcpy(*order,temp); + else strcat(*order,temp); + } +} + +enum xen_on_normal_exit +actionShutdownStringtoEnum(char *str) +{ + enum xen_on_normal_exit code = XEN_ON_NORMAL_EXIT_UNDEFINED; + if (STREQ(str, "destroy")) + code = XEN_ON_NORMAL_EXIT_DESTROY; + else if (STREQ(str, "restart")) + code = XEN_ON_NORMAL_EXIT_RESTART; + return code; +} + +enum xen_on_crash_behaviour +actionCrashStringtoEnum(char *str) +{ + enum xen_on_crash_behaviour code = XEN_ON_CRASH_BEHAVIOUR_UNDEFINED; + if (STREQ(str, "destroy")) + code = XEN_ON_CRASH_BEHAVIOUR_DESTROY; + else if (STREQ(str, "restart")) + code = XEN_ON_CRASH_BEHAVIOUR_RESTART; + else if (STREQ(str, "preserve")) + code = XEN_ON_CRASH_BEHAVIOUR_PRESERVE; + else if (STREQ(str, "rename-restart")) + code = XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART; + return code; +} + +/* convert boot order string libvirt format to XenServer format */ +const char * +mapXmlBootOrder(char c) { + switch(c) { + case 'a': + return "fd"; + case 'c': + return "hd"; + case 'd': + return "cdrom"; + case 'n': + return "network"; + default: + return NULL; + } +} + +/* creates network intereface for VM */ +int +createVifNetwork (virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac) +{ + xen_vm xvm = NULL; + char *uuid = NULL; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, vm); + if (uuid) { + if(!xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &xvm, uuid)) + return -1; + VIR_FREE(uuid); + } + xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc(); + vm_opt->is_record = 0; + vm_opt->u.handle = xvm; + xen_network_set *net_set = NULL; + xen_network_record *net_rec = NULL; + int cnt=0; + if (xen_network_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &net_set)) { + for(cnt=0;cnt<(net_set->size);cnt++) { + if (xen_network_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &net_rec, net_set->contents[cnt])) { + if (STREQ(net_rec->bridge,bridge)) { + break; + } else { + xen_network_record_free(net_rec); + } + } + } + } + if ( (cnt<net_set->size) && net_rec) { + xen_network network = NULL; + xen_network_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &network, net_rec->uuid); + xen_network_record_opt *network_opt = xen_network_record_opt_alloc(); + network_opt->is_record = 0; + network_opt->u.handle = network; + xen_vif_record *vif_record = xen_vif_record_alloc(); + vif_record->mac = mac; + vif_record->vm = vm_opt; + vif_record->network = network_opt; + xen_vif vif=NULL; + + vif_record->other_config = xen_string_string_map_alloc(0); + vif_record->runtime_properties = xen_string_string_map_alloc(0); + vif_record->qos_algorithm_params = xen_string_string_map_alloc(0); + vif_record->device = strdup(device); + xen_vif_create(((struct _xenapiPrivate *)(conn->privateData))->session, + &vif, vif_record); + if (vif!=NULL) { + xen_vif_free(vif); + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + xen_network_set_free(net_set); + return 0; + } + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + } + if (net_set!=NULL) xen_network_set_free(net_set); + return -1; +} + +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, const char *xmlDesc, + xen_vm_record **record, xen_vm *vm) +{ + xmlDocPtr doc; + xmlNodePtr cur,child,temp; + doc = xmlParseMemory(xmlDesc,strlen(xmlDesc)); + if (doc == NULL) { + xenapiSessionErrorHandler(conn,VIR_ERR_XML_ERROR ,"", __FILE__, __FUNCTION__, __LINE__); + return -1; + } + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + xenapiSessionErrorHandler(conn,VIR_ERR_XML_ERROR ,"", __FILE__, __FUNCTION__, __LINE__); + xmlFreeDoc(doc); + return -1; + } + if (xmlStrcmp(cur->name, (const xmlChar *) "domain")) { + xenapiSessionErrorHandler(conn,VIR_ERR_XML_ERROR ,"root node not domain", __FILE__, __FUNCTION__, __LINE__); + xmlFreeDoc(doc); + return -1; + } + *record = xen_vm_record_alloc(); + char *name = getXmlChildValue(doc,cur,"name"); + (*record)->name_label = strdup(name); + child = cur->xmlChildrenNode; + while (child!=NULL) { + if ((!xmlStrcmp(child->name, (const xmlChar *)"os"))) { + char *ostype = getXmlChildValue(doc,child,"type"); + if (ostype!=NULL) { + if (STREQ(ostype,"hvm")) { + (*record)->hvm_boot_policy = strdup("BIOS order"); + temp = child; + child = child->xmlChildrenNode; + char *boot_order = NULL; + while (child != NULL) { + if ((!xmlStrcmp(child->name, (const xmlChar *)"boot"))){ + xmlChar *key; + key = xmlGetProp(child, (const xmlChar *)"dev"); + if (key!=NULL) { + createXmlBootOrderString(&boot_order,(char *)key); + xmlFree(key); + } + } + child = child->next; + } + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + //int size = sizeof(xen_string_string_map) + + // (hvm_boot_params->size * sizeof(xen_string_string_map_contents)); + //(*record)->hvm_boot_params = (xen_string_string_map *) malloc(size); + //memcpy((char *)(*record)->hvm_boot_params, (char *)hvm_boot_params, size); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + //freeStringMap(hvm_boot_params); + } + child = temp; + } else if (STREQ(ostype,"linux")) { + (*record)->pv_bootloader = strdup("pygrub"); + char *kernel = getXmlChildValue(doc,child,"kernel"); + if (kernel != NULL){ + (*record)->pv_kernel = kernel; + //strcpy((*record)->pv_kernel,kernel); + //free(kernel); + } + char *initrd = getXmlChildValue(doc,child,"initrd"); + if (initrd != NULL) { + (*record)->pv_ramdisk = initrd;//(char *)malloc(strlen(initrd)+1); + //strcpy((*record)->pv_ramdisk,initrd); + //free(initrd); + } + char *cmdline = getXmlChildValue(doc,child,"cmdline"); + if (cmdline != NULL) { + (*record)->pv_args = cmdline; //(char *)malloc(strlen(cmdline)+1); + //strcpy((*record)->pv_args,cmdline); + //free(cmdline); + } + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + VIR_FREE(ostype); + } + } + child = child->next; + } + char *bootload_args = getXmlChildValue(doc,cur,"bootloader_args"); + if (bootload_args!=NULL) { + (*record)->pv_bootloader_args =bootload_args; //(char *)malloc(strlen(bootload_args)+1); + //strcpy((*record)->pv_bootloader_args,bootload_args); + //free(bootload_args); + } + char *memory = getXmlChildValue(doc,cur,"memory"); + if (memory!=NULL) { + int64_t static_max=0; + static_max = atoll(memory); + (*record)->memory_static_max = static_max * 1024; + VIR_FREE(memory); + } + char *curmemory = getXmlChildValue(doc,cur,"currentmemory"); + if (curmemory!=NULL) { + int64_t dy_max=0; + dy_max = atoll(curmemory); + (*record)->memory_dynamic_max = dy_max * 1024; + VIR_FREE(curmemory); + } else { + (*record)->memory_dynamic_max = (*record)->memory_static_max; + } + char *vcpu = getXmlChildValue(doc, cur, "vcpu"); + if (vcpu!=NULL) { + (*record)->vcpus_max = atoll(vcpu); + (*record)->vcpus_at_startup = atoll(vcpu); + VIR_FREE(vcpu); + } + char *on_poweroff = getXmlChildValue(doc,cur,"on_poweroff"); + if (on_poweroff!=NULL) { + (*record)->actions_after_shutdown = actionShutdownStringtoEnum(on_poweroff); + VIR_FREE(on_poweroff); + } + char *on_reboot = getXmlChildValue(doc,cur,"on_reboot"); + if (on_reboot!=NULL) { + (*record)->actions_after_reboot = actionShutdownStringtoEnum(on_reboot); + VIR_FREE(on_reboot); + } + char *on_crash = getXmlChildValue(doc,cur,"on_crash"); + if (on_crash!=NULL) { + (*record)->actions_after_crash = actionCrashStringtoEnum(on_crash); + VIR_FREE(on_crash); + } + temp = cur; + cur = cur->xmlChildrenNode; + xen_string_string_map *strings=NULL; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"features"))){ + for (child=cur->children;child!=NULL;child=child->next) { + allocStringMap(&strings,(char *)child->name,(char *)"true"); + } + } + cur = cur->next; + } + cur = temp; + if (strings!=NULL) { + //int size = sizeof(xen_string_string_map)+ sizeof(xen_string_string_map_contents)*strings->size; + (*record)->platform = strings; //(xen_string_string_map *)malloc(size); + //memcpy((void *)(*record)->platform,(void *)strings,size); + } + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xmlFreeDoc(doc); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR ,NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + cur = cur->xmlChildrenNode; + int device_number=0; + xmlChar *bridge=NULL,*mac=NULL; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"interface"))){ + for (child=cur->children;child!=NULL;child=child->next) { + if ((!xmlStrcmp(child->name, (const xmlChar *)"source"))) { + bridge = xmlGetProp(child, (const xmlChar *)"bridge"); + } + if ((!xmlStrcmp(child->name, (const xmlChar *)"mac"))) { + mac = xmlGetProp(child, (const xmlChar *)"address"); + } + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, (char *)bridge, (char *)mac); + xmlFree(bridge); + device_number++; + } + } + cur = cur->next; + } + xmlFreeDoc(doc); + return 0; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-02-18 16:28:10.000000000 +0000 @@ -0,0 +1,94 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#ifndef _VIR_XENAPI_UTILS_ +#define _VIR_XENAPI_UTILS_ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> +//#include <xen/dom0_ops.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" + +#define NETWORK_DEVID_SIZE (10) + +typedef uint64_t cpumap_t; + +void getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen); + +int getStorageVolumeType(char *type); + +char *returnErrorFromSession(xen_session *session); + +void xenapiSessionErrorHandler(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + + +virDomainState +mapPowerState(enum xen_vm_power_state state); + +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen); + +char * +getXmlChildValue(xmlDocPtr doc, xmlNodePtr cur, const char *tag); + +int +createVMRecordFromXml (virConnectPtr conn, const char *xmlDesc, + xen_vm_record **record, xen_vm *vm); + +int +allocStringMap (xen_string_string_map **strings, char *key, char *val); + +void +createXmlBootOrderString(char **order, char *key); + +enum xen_on_normal_exit +actionShutdownStringtoEnum(char *str); + +enum xen_on_crash_behaviour +actionCrashStringtoEnum(char *str); + +int +createVifNetwork(virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac); + +const char * +mapXmlBootOrder(char c); + + + + + + + +#endif //_VIR_XENAPI_UTILS_

On Fri, Feb 19, 2010 at 11:24:56AM +0000, Sharadha Prabhakar (3P) wrote:
diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-18 16:26:52.000000000 +0000 +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL; + bzero(cpumap, maplen); + num = strtok (mask, ","); + while (num != NULL) { + sscanf (num, "%d", &pos); + if (pos<0 || pos>max_bits-1) + printf ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok (NULL, ","); + } +}
Don't printf() if you find problems. If it is a non-fatal problem then use either VIR_INFO/VIR_WARN/VIR_DEBUG from logging.h. If it is fatal then use the error reporting API. The strtok() API is not allowed in libvirt, since it is not threadsafe. You'll likely want to use strtok_r() instead.
+/* create boot order string as understood by libvirt */ +void +createXmlBootOrderString(char **order, char *key) +{ + int sz = ((*order)==NULL)?0:(strlen(*order)+1); + const char *temp=NULL; + if (strcmp(key,"fd")==0) + temp="a"; + else if (strcmp(key,"hd")==0) + temp="c"; + else if (strcmp(key,"cdrom")==0) + temp="d"; + else if (strcmp(key,"network")==0) + temp="n";
Instead of strcmp(), use STREQ() for these.
+ +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, const char *xmlDesc, + xen_vm_record **record, xen_vm *vm)
This method is one that should accept a virDomainDefPtr rather than the raw XML document. That lets you re-use the standard XML parsing routines that are shared between drivers
+{ + xmlDocPtr doc; + xmlNodePtr cur,child,temp; + doc = xmlParseMemory(xmlDesc,strlen(xmlDesc)); + if (doc == NULL) { + xenapiSessionErrorHandler(conn,VIR_ERR_XML_ERROR ,"", __FILE__, __FUNCTION__, __LINE__); + return -1; + } + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + xenapiSessionErrorHandler(conn,VIR_ERR_XML_ERROR ,"", __FILE__, __FUNCTION__, __LINE__); + xmlFreeDoc(doc); + return -1; + } + if (xmlStrcmp(cur->name, (const xmlChar *) "domain")) { + xenapiSessionErrorHandler(conn,VIR_ERR_XML_ERROR ,"root node not domain", __FILE__, __FUNCTION__, __LINE__); + xmlFreeDoc(doc); + return -1; + } + *record = xen_vm_record_alloc(); + char *name = getXmlChildValue(doc,cur,"name"); + (*record)->name_label = strdup(name); + child = cur->xmlChildrenNode; + while (child!=NULL) { + if ((!xmlStrcmp(child->name, (const xmlChar *)"os"))) { + char *ostype = getXmlChildValue(doc,child,"type"); + if (ostype!=NULL) { + if (STREQ(ostype,"hvm")) { + (*record)->hvm_boot_policy = strdup("BIOS order"); + temp = child; + child = child->xmlChildrenNode; + char *boot_order = NULL; + while (child != NULL) { + if ((!xmlStrcmp(child->name, (const xmlChar *)"boot"))){ + xmlChar *key; + key = xmlGetProp(child, (const xmlChar *)"dev"); + if (key!=NULL) { + createXmlBootOrderString(&boot_order,(char *)key); + xmlFree(key); + } + } + child = child->next; + } + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + //int size = sizeof(xen_string_string_map) + + // (hvm_boot_params->size * sizeof(xen_string_string_map_contents)); + //(*record)->hvm_boot_params = (xen_string_string_map *) malloc(size); + //memcpy((char *)(*record)->hvm_boot_params, (char *)hvm_boot_params, size); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + //freeStringMap(hvm_boot_params); + } + child = temp; + } else if (STREQ(ostype,"linux")) { + (*record)->pv_bootloader = strdup("pygrub"); + char *kernel = getXmlChildValue(doc,child,"kernel"); + if (kernel != NULL){ + (*record)->pv_kernel = kernel; + //strcpy((*record)->pv_kernel,kernel); + //free(kernel); + } + char *initrd = getXmlChildValue(doc,child,"initrd"); + if (initrd != NULL) { + (*record)->pv_ramdisk = initrd;//(char *)malloc(strlen(initrd)+1); + //strcpy((*record)->pv_ramdisk,initrd); + //free(initrd); + } + char *cmdline = getXmlChildValue(doc,child,"cmdline"); + if (cmdline != NULL) { + (*record)->pv_args = cmdline; //(char *)malloc(strlen(cmdline)+1); + //strcpy((*record)->pv_args,cmdline); + //free(cmdline); + } + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + VIR_FREE(ostype); + } + } + child = child->next; + } + char *bootload_args = getXmlChildValue(doc,cur,"bootloader_args"); + if (bootload_args!=NULL) { + (*record)->pv_bootloader_args =bootload_args; //(char *)malloc(strlen(bootload_args)+1); + //strcpy((*record)->pv_bootloader_args,bootload_args); + //free(bootload_args); + } + char *memory = getXmlChildValue(doc,cur,"memory"); + if (memory!=NULL) { + int64_t static_max=0; + static_max = atoll(memory); + (*record)->memory_static_max = static_max * 1024; + VIR_FREE(memory); + } + char *curmemory = getXmlChildValue(doc,cur,"currentmemory"); + if (curmemory!=NULL) { + int64_t dy_max=0; + dy_max = atoll(curmemory); + (*record)->memory_dynamic_max = dy_max * 1024; + VIR_FREE(curmemory); + } else { + (*record)->memory_dynamic_max = (*record)->memory_static_max; + } + char *vcpu = getXmlChildValue(doc, cur, "vcpu"); + if (vcpu!=NULL) { + (*record)->vcpus_max = atoll(vcpu); + (*record)->vcpus_at_startup = atoll(vcpu); + VIR_FREE(vcpu); + } + char *on_poweroff = getXmlChildValue(doc,cur,"on_poweroff"); + if (on_poweroff!=NULL) { + (*record)->actions_after_shutdown = actionShutdownStringtoEnum(on_poweroff); + VIR_FREE(on_poweroff); + } + char *on_reboot = getXmlChildValue(doc,cur,"on_reboot"); + if (on_reboot!=NULL) { + (*record)->actions_after_reboot = actionShutdownStringtoEnum(on_reboot); + VIR_FREE(on_reboot); + } + char *on_crash = getXmlChildValue(doc,cur,"on_crash"); + if (on_crash!=NULL) { + (*record)->actions_after_crash = actionCrashStringtoEnum(on_crash); + VIR_FREE(on_crash); + } + temp = cur; + cur = cur->xmlChildrenNode; + xen_string_string_map *strings=NULL; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"features"))){ + for (child=cur->children;child!=NULL;child=child->next) { + allocStringMap(&strings,(char *)child->name,(char *)"true"); + } + } + cur = cur->next; + } + cur = temp; + if (strings!=NULL) { + //int size = sizeof(xen_string_string_map)+ sizeof(xen_string_string_map_contents)*strings->size; + (*record)->platform = strings; //(xen_string_string_map *)malloc(size); + //memcpy((void *)(*record)->platform,(void *)strings,size); + } + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xmlFreeDoc(doc); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR ,NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + cur = cur->xmlChildrenNode; + int device_number=0; + xmlChar *bridge=NULL,*mac=NULL; + while (cur != NULL) { + if ((!xmlStrcmp(cur->name, (const xmlChar *)"interface"))){ + for (child=cur->children;child!=NULL;child=child->next) { + if ((!xmlStrcmp(child->name, (const xmlChar *)"source"))) { + bridge = xmlGetProp(child, (const xmlChar *)"bridge"); + } + if ((!xmlStrcmp(child->name, (const xmlChar *)"mac"))) { + mac = xmlGetProp(child, (const xmlChar *)"address"); + } + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, (char *)bridge, (char *)mac); + xmlFree(bridge); + device_number++; + } + } + cur = cur->next; + } + xmlFreeDoc(doc); + return 0; +} +
Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This is a patch to add XenAPI driver support for libvirt version 0.7.6. XenAPI can be used against XenCloud platform and managed through virsh and virt-manger. This patch supports domain related APIs in libvirt. It is possible to get domain information, list active and inactive domains, get Domain XML configuration and Start/stop/pause/shutdown/destroy VMs. There will be more patches after this review to support more libvirt APIs and add remote storage support to XenAPI. In order to run this patch you would require libxenserver library. Libxenserver library can be downloaded from http://community.citrix.com/download/attachments/38633496/libxenserver-5.5.0... Copy the libxenserver folder in the same directory level as libvirt.
I don't really like this idea of downloading libxenserver to a special location relative to libvirt and then building/linking against it especially as libvirt will use libxenserver shared library. How would you install libvirt build in such environment? It is much better to require libxenserver package to be installed in the same way as other dependencies are required and then detect it in configure.ac. Then, you can use --with=libxenserver=path if it's installed in some special path. Also make sure libvirt compiles after every single patch from your series. Especially, you shouldn't change makefiles before the new source files are introduced. Jirka

On Fri, Feb 19, 2010 at 11:14:53AM +0000, Sharadha Prabhakar (3P) wrote:
Resending patches in plain text. ~/Libvirt/Src/Makefile.am contains some changes suggested by Daniel Veillard.
This is a patch to add XenAPI driver support for libvirt version 0.7.6. XenAPI can be used against XenCloud platform and managed through virsh and virt-manger. This patch supports domain related APIs in libvirt. It is possible to get domain information, list active and inactive domains, get Domain XML configuration and Start/stop/pause/shutdown/destroy VMs. There will be more patches after this review to support more libvirt APIs and add remote storage support to XenAPI. In order to run this patch you would require libxenserver library. Libxenserver library can be downloaded from http://community.citrix.com/download/attachments/38633496/libxenserver-5.5.0... Copy the libxenserver folder in the same directory level as libvirt. The XenCloud platform can be downloaded from http://xen.org/products/cloudxen.html
diff -ur ./libvirt_org/configure.ac ./libvirt/configure.ac --- ./libvirt_org/configure.ac 2010-02-17 17:39:21.000000000 +0000 +++ ./libvirt/configure.ac 2010-02-18 11:51:29.000000000 +0000 @@ -219,6 +219,8 @@ AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes]) AC_ARG_WITH([phyp], AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check]) +AC_ARG_WITH([xenapi], + AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=yes@:>@]),[],[with_xenapi=check]) AC_ARG_WITH([vbox], AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes]) AC_ARG_WITH([lxc], @@ -307,6 +309,11 @@ fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"])
+if test "$with_xenapi" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi +AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"])
This should really be checking for the libxenserver library. I'd expect the behaviour to be --with-xenapi -> check for the libxenserver in regular compiler/linker paths (ie let it default to /usr/include & /usr/lib) --with-xenapi=/some/dir -> set CFLAGS=-I/some/dir/include LDFLAGS=-L/some/dir/lib once it is found then export two variables to the makefile LIBXENSERVER_CFLAGS LIBXENSERVER_LDFLAGS
+ if test "$with_libvirtd" = "no" ; then with_qemu=no fi @@ -1894,6 +1901,7 @@ AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ PHYP: $with_phyp]) AC_MSG_NOTICE([ ONE: $with_one]) Binary files ./libvirt_org/daemon/.libs/libvirtd and ./libvirt/daemon/.libs/libvirtd differ Only in ./libvirt_org/daemon/.libs: lt-libvirtd
--- ./libvirt_org/src/Makefile.am 2010-02-17 17:38:13.000000000 +0000 +++ ./libvirt/src/Makefile.am 2010-02-19 10:55:51.000000000 +0000 @@ -3,12 +3,19 @@ # No libraries with the exception of LIBXML should be listed # here. List them against the individual XXX_la_CFLAGS targets # that actually use them + +XENAPI_CFLAGS = -I@top_srcdir@/../libxenserver/include +
This is not required if variables are exported from the configure.ac script
INCLUDES = \ -I$(top_srcdir)/gnulib/lib \ -I../gnulib/lib \ -I../include \ + -I/usr/include \ -I@top_srcdir@/src/util \ + -I@top_srcdir@/src \ + -I@top_srcdir@/src/xenapi \ -I@top_srcdir@/include \ + $(XENAPI_CFLAGS) \ $(DRIVER_MODULE_CFLAGS) \ $(LIBXML_CFLAGS) \ -DLIBDIR=\""$(libdir)"\" \
The global INCLUDES variable should not contain any driver specific rules - this is only for stuff shared between drivers
@@ -42,6 +49,9 @@ augeastestdir = $(datadir)/augeas/lenses/tests augeastest_DATA =
+XENAPI_LIBS = @top_srcdir@/../libxenserver/libxenserver.so +XENAPI_LDFLAGS = -L@top_srcdir@/../libxenserver/ -lxenserver
Also redundant if exported from configure.ac
+ # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ @@ -205,6 +215,10 @@ qemu/qemu_security_dac.h \ qemu/qemu_security_dac.c
+XENAPI_DRIVER_SOURCES = \ + xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ + xenapi/xenapi_utils.c xenapi/xenapi_utils.h + UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ uml/uml_driver.c uml/uml_driver.h @@ -466,6 +480,28 @@ libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES) endif
+if WITH_XENAPI +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xenapi.la +else +noinst_LTLIBRARIES += libvirt_driver_xenapi.la + +libvirt_la_LIBADD += libvirt_driver_xenapi.la \ + $(XENAPI_LIBS) +endif +#libvirt_driver_xenapi_la_LIBADD = $(XENAPI_LIBS) +libvirt_driver_xenapi_la_CFLAGS = $(XEN_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(shell curl-config --cflags) +libvirt_driver_xenapi_la_LDFLAGS = $(XENAPI_LDFLAGS) -g $(LIBXML_LIBS) \ + $(shell curl-config --libs)
I think you mean XENAPI_CFLAGS here, not XEN_CFLAGS. Also the probing for curl should be done from configure.ac. Indeed it already checks for libcurl, so you just need to reference the existing LIBCURL_CFLAGS/LDFALGS. There's no need for LIBXML_CFLAGS here, since that's in the global INCLUDES already
+ +if WITH_DRIVER_MODULES +libvirt_driver_xenapi_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES) +endif + if WITH_QEMU if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_qemu.la @@ -722,6 +758,7 @@ $(OPENVZ_DRIVER_SOURCES) \ $(PHYP_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ + $(XENAPI_DRIVER_SOURCES) \ $(ESX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \
diff -ur ./libvirt_org/tools/Makefile.am ./libvirt/tools/Makefile.am --- ./libvirt_org/tools/Makefile.am 2010-02-17 17:36:13.000000000 +0000 +++ ./libvirt/tools/Makefile.am 2010-02-18 11:56:30.000000000 +0000 @@ -40,7 +40,8 @@ $(WARN_CFLAGS) \ ../src/libvirt.la \ ../gnulib/lib/libgnu.la \ - $(VIRSH_LIBS) + $(VIRSH_LIBS) \ + ../../libxenserver/libxenserver.so virsh_CFLAGS = \ -I$(top_srcdir)/gnulib/lib -I../gnulib/lib \ -I../include -I$(top_srcdir)/include \
This change should not be required - virsh links to the public libvirt API only, never the stuff used by the internal drivers Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

This patch contains XenAPI driver specific files. Files included are xenapi_driver.c xenapi_utils.c xenapi_driver.h xenapi_driver_private.h xenapi_utils.h This patch includes changes suggested in the first review. diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "esx/esx_util.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url=NULL; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = esxUtil_RequestPassword(auth,conn->uri->user,conn->uri->server); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + virAsprintf(&url,"https://%s",conn->uri->server); + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, conn->uri->user, passwd, xen_api_latest_version); + + if ( session && session->ok ) { + if (VIR_ALLOC(privP)<0) + return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + VIR_FREE(url); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL); + return -1; + } + xen_string_string_map *result=NULL; + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val); + } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release); + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL); + return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +static virCapsPtr +getCapsObject(void) +{ + virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64"); + caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen"); + return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virCapsPtr caps = getCapsObject(); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps); + VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL); + + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_uuid(session, &vm, (char *)uuid)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(session, &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + } + return NULL; + } + } + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN,"Domain name not found"); + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup("hvm"); + } else { + os_version = strdup("xen"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(session, vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(session, vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) return -1; + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL; + if (VIR_ALLOC(defPtr)<0) + return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + strcpy((char *)defPtr->uuid,(char *)dom->uuid); + defPtr->name = strdup(dom->name); + + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm"); + xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux"); + defPtr->os.loader = strdup("pygrub"); + + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub"); + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + return NULL; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + return NULL; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0); +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML"); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_host_metrics_get_all(session, &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(session, (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information"); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics"); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + NULL, /* domainXmlFromNative */ + NULL, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, + NULL, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + NULL, /* domainGetSchedulerParameters */ + NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ + NULL, + NULL, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + NULL, /* nodeDeviceDettach */ + NULL, /* nodeDeviceReAttach */ + NULL, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-26 13:21:50.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_PRIV_H__ +#define __VIR_XENAPI_PRIV_H__ + + +extern int xenapiRegister (void); + + +#endif /* __VIR_XENAPI_PRIV_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-02-26 15:15:55.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> + +#define PRINT_XML +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "domain_conf.h" +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" +#include "util/logging.h" + + + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_normal_exit num = XEN_ON_NORMAL_EXIT_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_NORMAL_EXIT_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_NORMAL_EXIT_RESTART; + return num; +} + + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_crash_behaviour num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_CRASH_BEHAVIOUR_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + else if (action == VIR_DOMAIN_LIFECYCLE_PRESERVE) + num = XEN_ON_CRASH_BEHAVIOUR_PRESERVE; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART_RENAME) + num = XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART; + return num; +} + +/* generate XenAPI boot order format from libvirt format */ +char * +createXenAPIBootOrderString(int nboot, int *bootDevs) +{ + virBuffer ret = VIR_BUFFER_INITIALIZER; + char *val = NULL; + int i; + for (i=0;i<nboot;i++) { + if (bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) + val = (char *)"a"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_DISK) + val = (char *)"c"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) + val = (char *)"d"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_NET) + val = (char *)"n"; + if (val) + virBufferEscapeString(&ret,"%s",val); + } + return virBufferContentAndReset(&ret); +} + +/* convert boot order string to libvirt boot order enum */ +enum virDomainBootOrder +map2LibvirtBootOrder(char c) { + switch(c) { + case 'a': + return VIR_DOMAIN_BOOT_FLOPPY; + case 'c': + return VIR_DOMAIN_BOOT_DISK; + case 'd': + return VIR_DOMAIN_BOOT_CDROM; + case 'n': + return VIR_DOMAIN_BOOT_NET; + default: + return -1; + } +} + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_NORMAL_EXIT_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_NORMAL_EXIT_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + return num; +} + + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_CRASH_BEHAVIOUR_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + else if (action == XEN_ON_CRASH_BEHAVIOUR_PRESERVE) + num = VIR_DOMAIN_LIFECYCLE_PRESERVE; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART_RENAME; + return num; +} + + + +/* returns 'file' or 'block' for the storage type */ +int +getStorageVolumeType(char *type) +{ + if((STREQ(type,"lvmoiscsi")) || + (STREQ(type,"lvmohba")) || + (STREQ(type,"lvm")) || + (STREQ(type,"file")) || + (STREQ(type,"iso")) || + (STREQ(type,"ext")) || + (STREQ(type,"nfs"))) + return (int)VIR_STORAGE_VOL_FILE; + else if((STREQ(type,"iscsi")) || + (STREQ(type,"equal")) || + (STREQ(type,"hba")) || + (STREQ(type,"cslg")) || + (STREQ(type,"udev")) || + (STREQ(type,"netapp"))) + return (int)VIR_STORAGE_VOL_BLOCK; + return -1; +} + +/* returns error description if any received from the server */ +char * +returnErrorFromSession(xen_session *session) +{ + int i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + for (i=0; i<session->error_description_count-1; i++) { + if (!i) + virBufferEscapeString(&buf,"%s",session->error_description[i]); + else + virBufferEscapeString(&buf," : %s",session->error_description[i]); + } + return virBufferContentAndReset(&buf); +} + +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf); + } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr); + return ret; +} + +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL,*bp=NULL; + bzero(cpumap, maplen); + num = strtok_r (mask, ",", &bp); + while (num != NULL) { + sscanf (num, "%d", &pos); + if (pos<0 || pos>max_bits-1) + VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok_r (NULL, ",", &bp); + } +} + + +/* mapping XenServer power state to Libvirt power state */ +virDomainState +mapPowerState(enum xen_vm_power_state state) +{ + virDomainState virState; + switch (state) { + case (XEN_VM_POWER_STATE_HALTED): + case (XEN_VM_POWER_STATE_SUSPENDED): + virState = VIR_DOMAIN_SHUTOFF; + break; + case (XEN_VM_POWER_STATE_PAUSED): + virState = VIR_DOMAIN_PAUSED; + break; + case (XEN_VM_POWER_STATE_RUNNING): + virState = VIR_DOMAIN_RUNNING; + break; + case (XEN_VM_POWER_STATE_UNKNOWN): + case (XEN_VM_POWER_STATE_UNDEFINED): + virState = VIR_DOMAIN_NOSTATE; + break; + default: + virState = VIR_DOMAIN_NOSTATE; + break; + } + return virState; +} + +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) + return -1; + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val); + return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} + +/* creates network intereface for VM */ +int +createVifNetwork (virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac) +{ + xen_vm xvm = NULL; + char *uuid = NULL; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, vm); + if (uuid) { + if(!xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &xvm, uuid)) + return -1; + VIR_FREE(uuid); + } + xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc(); + vm_opt->is_record = 0; + vm_opt->u.handle = xvm; + xen_network_set *net_set = NULL; + xen_network_record *net_rec = NULL; + int cnt=0; + if (xen_network_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &net_set)) { + for(cnt=0;cnt<(net_set->size);cnt++) { + if (xen_network_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &net_rec, net_set->contents[cnt])) { + if (STREQ(net_rec->bridge,bridge)) { + break; + } else { + xen_network_record_free(net_rec); + } + } + } + } + if ( (cnt<net_set->size) && net_rec) { + xen_network network = NULL; + xen_network_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &network, net_rec->uuid); + xen_network_record_opt *network_opt = xen_network_record_opt_alloc(); + network_opt->is_record = 0; + network_opt->u.handle = network; + xen_vif_record *vif_record = xen_vif_record_alloc(); + vif_record->mac = mac; + vif_record->vm = vm_opt; + vif_record->network = network_opt; + xen_vif vif=NULL; + + vif_record->other_config = xen_string_string_map_alloc(0); + vif_record->runtime_properties = xen_string_string_map_alloc(0); + vif_record->qos_algorithm_params = xen_string_string_map_alloc(0); + vif_record->device = strdup(device); + xen_vif_create(((struct _xenapiPrivate *)(conn->privateData))->session, + &vif, vif_record); + if (vif!=NULL) { + xen_vif_free(vif); + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + xen_network_set_free(net_set); + return 0; + } + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + } + if (net_set!=NULL) xen_network_set_free(net_set); + return -1; +} + +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + *record = xen_vm_record_alloc(); + (*record)->name_label = strdup(def->name); + if (STREQ(def->os.type,"hvm")) { + (*record)->hvm_boot_policy = strdup("BIOS order"); + char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + (*record)->pv_bootloader = strdup("pygrub"); + (*record)->pv_kernel = def->os.kernel; + (*record)->pv_ramdisk = def->os.initrd; + (*record)->pv_args = def->os.cmdline; + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + (*record)->pv_bootloader_args = def->os.bootloaderArgs; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<0)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<1)) + allocStringMap(&strings,(char *)"apci",(char *)"true"); + if (def->features & (1<<2)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + } + if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + bridge = strdup(def->nets[i]->data.bridge.brname); + if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + mac = strdup(macStr); + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + } + + } + } + return 0; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-02-26 13:24:19.000000000 +0000 @@ -0,0 +1,86 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#ifndef _VIR_XENAPI_UTILS_ +#define _VIR_XENAPI_UTILS_ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "conf/domain_conf.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" + +#define NETWORK_DEVID_SIZE (10) + +typedef uint64_t cpumap_t; + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +char * +createXenAPIBootOrderString(int nboot, int *bootDevs); + +enum virDomainBootOrder map2LibvirtBootOrder(char c); + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action); + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action); + +void getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen); + +int getStorageVolumeType(char *type); + +char *returnErrorFromSession(xen_session *session); + +virDomainState +mapPowerState(enum xen_vm_power_state state); + +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen); + +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr defPtr, + xen_vm_record **record, xen_vm *vm); + +int +allocStringMap (xen_string_string_map **strings, char *key, char *val); + +int +createVifNetwork(virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac); + +#endif //_VIR_XENAPI_UTILS_

2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
This patch contains XenAPI driver specific files. Files included are xenapi_driver.c xenapi_utils.c xenapi_driver.h xenapi_driver_private.h xenapi_utils.h This patch includes changes suggested in the first review.
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ +
+ +char *url=NULL;
You should move this into the xenapiPrivate struct, otherwise you'll have trouble using multiple XenAPI connections at the same time, because multiple calls to xenapiOpen will overwrite the pointer an leak the previous value.
+/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_ERROR;
If the URI is not for you (scheme != XenAPI) then you must decline it (return VIR_DRV_OPEN_DECLINED) and not return VIR_DRV_OPEN_ERROR. All other schemes in libvirt are lowercase. I suggest you change it to "xenapi" or switch the STREQ to STRCASEEQ to do a case-insensitive comparison.
+ } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = esxUtil_RequestPassword(auth,conn->uri->user,conn->uri->server);
You cannot use ESX driver code here, because inter-driver dependencies are forbidden. So we could either move this function into the src/utils/utils.c or you duplicate the function in the XenAPI driver code. I suggest the later because esxUtil_RequestPassword's behavior is special for the ESX driver (setting the challenge to the hostname).
+ } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + virAsprintf(&url,"https://%s",conn->uri->server);
You should check the return value from virAsprintf and report an OOM error if the return value is negative.
+ xmlInitParser(); + xmlKeepBlanksDefault(0);
I'm not sure if it's a good idea to change global libxml2 defaults. I can't tell if this is the default anyway, or if it'll will affect the other XML parsing code in libvirt in a negative way, because the libxml2 documentation for this function is confusing to me.
+ xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, conn->uri->user, passwd, xen_api_latest_version); + + if ( session && session->ok ) { + if (VIR_ALLOC(privP)<0)
You need to call virReportOOMError() here, to report the allocation failure.
+ return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + return VIR_DRV_OPEN_ERROR; + } +} +
+ +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} +
+ +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
Remove ATTRIBUTE_UNUSED from conn, as conn is used in this function.
+{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return -1; + } + xen_string_string_map *result=NULL;
You should define new variables always at the beginning of a block.
+ if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val);
You need to check the return value strdup of for NULL and report an OOM error using virReportOOMError if it's NULL. Also you need to break the for loop if you found the version string, otherwise you may strdup and assign a string multiple times to version and leak the previous allocated memeory.
+ } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release);
You should check the return value of sscanf to see if it failed.
+ *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} +
+ +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2);
You should use virStrncpy here and check its return value.
+ info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +static virCapsPtr +getCapsObject(void) +{
You're not supposed to build the caps structure by hand. Use the virCapabilities* functions.
+ virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64");
Use virCapabilitiesNew instead.
+ caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen");
Use virCapabilitiesAddGuest and virCapabilitiesAddGuestDomain instead.
+ return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virCapsPtr caps = getCapsObject(); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps);
You could improve this by creating the caps once per connection and store the virCapsPtr in the xenapiPrivate struct, instead of recreating it over and over again.
+ VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size;
That's wrong. Assume the case that result->size is greater than maxids, then you are reporting back more IDs than you actually wrote to the ids array.
+ xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid);
createVMRecordFromXml doesn't copy the UUID from the virDomainDefPtr to the xen_vm_record, so parsing it here gives wrong results.
+ if (vm!=NULL) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid);
You forgot to set the domain ID (domP->id).
+ xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
You're leaking the caps object here.
+ return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record);
You should break the for loop if the domain id found.
+ } + }
You should report an error if the domain is not found.
+ xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_uuid(session, &vm, (char *)uuid)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid);
const unsigned char *uuid is already in raw format. Parsing it again will give wrong results. Did you actually test this function?
+ domP = virGetDomain(conn, record->name_label, raw_uuid);
The domain ID should be set here.
+ xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} +
+ +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + }
Is vms->contents[0] guaranteed to be valid if xen_vm_get_by_name_label succeeds?
+ vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Okay you check vms->size here before accessing vms->contents[0]. So you should do the same in xenapiDomainSuspend.
+ if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
vms->size check missing here as in xenapiDomainSuspend.
+ vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} +
+ +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) {
Is distro != windows a good indicator for paravirtualization mode? How do you detect the case when you have a non-windows system in HVM mode?
+ os_version = strdup("hvm");
OOM check missing.
+ } else { + os_version = strdup("xen");
OOM check missing.
+ } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + if ( os_version == NULL ) { + os_version = strdup("unknown");
OOM check missing.
+ } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms != NULL && vms->size!=0) {
Maybe you should unify the way you check for a valid vm set, because you do it both ways around.
+ /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} +
+ +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
You forget to check for a valid vm set.
+ vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +
+ +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen);
value leaks.
+ xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) return -1;
You call should call virReportOOMError in case of an allcoation error.
+ if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Check for a valid vm set is missing.
+ vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val);
Break the for look here an check for OOM error here.
+ } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + }
mask leaks.
+ return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
Check for a valid vm set is missing.
+ vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL;
Use virDomainDefPtr.
+ if (VIR_ALLOC(defPtr)<0)
virReportOOMError missing.
+ return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + strcpy((char *)defPtr->uuid,(char *)dom->uuid);
You cannot copy a raw UUID using strcpy, becaue it isn't a string an can contain 0 values. But strcpy will stop at the first 0 value. Use memcpy(defPtr->uuid, dom->uuid, VIR_UUID_BUFLEN) instead.
+ defPtr->name = strdup(dom->name);
OOM check missing.
+ char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm");
OOM check missing.
+ xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux");
Use xen instead of linux.
+ defPtr->os.loader = strdup("pygrub");
OOM checks missing.
+ + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub");
OOM check missing.
+ } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val);
OOM check missing. Also use STRNEQ instead of !STREQ.
+ VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0);
Use VIR_DOMAIN_FEATURE_ACPI instead of 0.
+ else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1);
Use VIR_DOMAIN_FEATURE_APIC instead of 1.
+ else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2);
Use VIR_DOMAIN_FEATURE_PAE instead of 2.
+ } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) {
virReportOOMError missing.
+ return NULL; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) {
virReportOOMError missing.
+ return NULL; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge);
Why strdup'ing and freeing bridge? Why not assign it directly?
+ } + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0);
You're leaking defPtr here. Free it using virDomainDefFree.
+} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label);
OOM check missing.
+ names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL);
You're abusing VIR_ERR_NO_DEVICE here.
+ return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL);
You're abusing VIR_ERR_NO_DEVICE here.
+ return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else {
You're potentially leaking vms here, because if vms is not NULL but vms->size is then you goto the else branch and vms leaks. I just noticed this pattern here, but this affects probably several functions.
+ xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML");
You're leaking defPtr here. Free it using virDomainDefFree.
+ return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm);
You're leaking defPtr here. Free it using virDomainDefFree.
+ return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Again, missing check for a valid vm set.
+ vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Missing check for a valid vm set.
+ vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Missing check for a valid vm set.
+ vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit";
Don't return a const string here. The result is suppoed to be allocated. You need to strdup it and don't forget the OOM check.
+} +
+ +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells)
Remove ATTRIBUTE_UNUSED from freeMems.
+{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} +
+ +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
You should set CURLOPT_SSL_VERIFYHOST to 2, with 1 the common name field is ignored. Or just don't change the SSL config. libcurl defaults to secure settings.
+ CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} +
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-02-26 15:15:55.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> + +#define PRINT_XML +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
+ +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf);
Use the virBuffer API instea of snprintf and strcat.
+ } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr);
Use virAsprintf instead of snprintf and strdup.
+ return ret; +} +
+ +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) + return -1; + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val);
OOM check missing.
+ return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} +
+ +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + *record = xen_vm_record_alloc(); + (*record)->name_label = strdup(def->name);
OOM check missing. As mentioned before, you're forgot to copy the UUID here.
+ if (STREQ(def->os.type,"hvm")) { + (*record)->hvm_boot_policy = strdup("BIOS order");
OOM check missing.
+ char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + (*record)->pv_bootloader = strdup("pygrub");
OOM check missing.
+ (*record)->pv_kernel = def->os.kernel; + (*record)->pv_ramdisk = def->os.initrd; + (*record)->pv_args = def->os.cmdline; + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + (*record)->pv_bootloader_args = def->os.bootloaderArgs; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<0)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<1)) + allocStringMap(&strings,(char *)"apci",(char *)"true"); + if (def->features & (1<<2)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + }
Use the virDomainFeature enum values here too.
+ if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + bridge = strdup(def->nets[i]->data.bridge.brname);
OOM check missing.
+ if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + mac = strdup(macStr);
OOM check missing.
+ } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + }
You need to free bridge here in the case mac is NULL but bridge is not.
+ } + } + return 0; +} +
Matthias

2010/2/26 Matthias Bolte <matthias.bolte@googlemail.com>:
2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
This patch contains XenAPI driver specific files. Files included are xenapi_driver.c xenapi_utils.c xenapi_driver.h xenapi_driver_private.h xenapi_utils.h This patch includes changes suggested in the first review.
+/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_uuid(session, &vm, (char *)uuid)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid);
const unsigned char *uuid is already in raw format. Parsing it again will give wrong results. Did you actually test this function?
Okay, I take this one back. You use the domain name for lookup in other functions, so a broken UUID may not surface in manual tests. Matthias

This patch contains most of the changes suggested by Matthias Bolte. The Uri also supports an optional SSL verification flag. "xenapi://usrname@server?no_verify=1" will disable SSL verification. Could someone review the virDomainGetVcpus and virDomainPinVcpus in particular to ensure that's the implementation libvirt expects out of these APIs. Patch 2/2 is not sent as it contains no changes from the last review. Regards, Sharadha diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-03-03 14:15:41.000000000 +0000 @@ -0,0 +1,1771 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url=NULL; +int SSL_flag = 2; + +static virCapsPtr +getCapsObject (void) +{ + virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0); + if (!caps) { + virReportOOMError(); + return NULL; + } + virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0, NULL, NULL, 0, NULL); + if (!guest1) + goto error_cleanup; + virCapsGuestDomainPtr domain1 = virCapabilitiesAddGuestDomain(guest1, "xen", NULL, NULL, 0, NULL); + if (!domain1) + goto error_cleanup; + virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0, NULL, NULL, 0, NULL); + if (!guest2) + goto error_cleanup; + virCapsGuestDomainPtr domain2 = virCapabilitiesAddGuestDomain(guest2, "xen", NULL, NULL, 0, NULL); + if (!domain2) + goto error_cleanup; + + return caps; + + error_cleanup: + virCapabilitiesFree(caps); + return NULL; +} + +static void +SSLverify(char *uri) +{ + char *tmp=NULL,*str=NULL,*str1=NULL,*str2=NULL; + str1 = strtok_r(uri,"?",&tmp); + if (!str1) return; + str2 = strtok_r(NULL,"?",&tmp); + str = strtok_r(str2,"=",&tmp); + if(!str) return; + str1 = strtok_r(NULL,"=",&tmp); + if(STREQ(str,"no_verify")) { + if(STREQ(str1,"1")) + SSL_flag=0; + } +} + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd,*uri=NULL; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STRCASEEQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_DECLINED; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (virAsprintf(&url,"https://%s",conn->uri->server) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = xenapiUtil_RequestPassword(auth,conn->uri->user,conn->uri->server); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + + if (!(uri=virConnectGetURI(conn))) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , + "Could not get URI: SSL verification flag may be ignored"); + SSLverify(uri); + VIR_FREE(uri); + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, conn->uri->user, "xenroot", xen_api_latest_version); + + if ( session && session->ok ) { + if (VIR_ALLOC(privP) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + privP->session = session; + conn->privateData = privP; + virCapsPtr caps = getCapsObject(); + if (caps) + privP->caps = caps; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + virCapabilitiesFree(((struct _xenapiPrivate *)(conn->privateData))->caps); + VIR_FREE(conn->privateData); + VIR_FREE(url); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_string_string_map *result=NULL; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return -1; + } + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for (i=0; i<result->size; i++) { + if (STREQ(result->contents[i].key,"xen")) { + if (!(version = strdup(result->contents[i].val))) { + xen_string_string_map_free(result); + virReportOOMError(); + return -1; + } + break; + } + } + if (version) { + unsigned long major=0,minor=0,release=0; + if (sscanf(version,"%ld.%ld.%ld",&major,&minor,&release)!=3) { + virReportOOMError(); + xen_string_string_map_free(result); + VIR_FREE(version); + return -1; + } + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + //strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + //info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + if (!virStrncpy(info->model,modelname,LIBVIRT_MODELNAME_LEN-1,LIBVIRT_MODELNAME_LEN)){ + virReportOOMError(); + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return -1; + } + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn) +{ + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (caps) { + char *xml = virCapabilitiesFormatXML(caps); + return xml; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Capabilities not available"); + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + + if (result != NULL) { + int i; + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + xen_vm_set_free(result); + return i; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + virDomainDefFree(defPtr); + if (record) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (!domP) { + xen_vm_record_free(record); + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Domain Pointer is invalid"); + return domP; + } + domP->id = record->domid; + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , "Domain Pointer not valid"); + domP = NULL; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + break; + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + char uuidStr[VIR_UUID_STRING_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virUUIDFormat(uuid,uuidStr); + if (xen_vm_get_by_uuid(session, &vm, uuidStr)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + domP = virGetDomain(conn, record->name_label, uuid); + if (!domP) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , "Domain Pointer not valid"); + domP=NULL; + } else { + domP->id = record->domid; + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, (char *)name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + xen_vm_get_uuid(session, &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + } + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + if (!(os_version = strdup("hvm"))) { + virReportOOMError(); + xen_string_string_map_free(result); + xen_vm_record_free(record); + return NULL; + } + break; + } else { + if (!(os_version = strdup("xen"))) { + virReportOOMError(); + xen_string_string_map_free(result); + xen_vm_record_free(record); + return NULL; + } + break; + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return 0; + } + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(session, vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(session, vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value=NULL; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if ((value = mapDomainPinVcpu(vcpu, cpumap, maplen))) { + xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + VIR_FREE(value); + return 0; + } + VIR_FREE(value); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) { + virReportOOMError(); + return -1; + } + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) return -1; + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xen_vm_set_free(vms); + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + if (!(mask = strdup(vcpu_params->contents[i].val))){ + xen_vm_set_free(vms); + xen_string_string_map_free(vcpu_params); + virReportOOMError(); + return -1; + } + break; + } + } + xen_string_string_map_free(vcpu_params); + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + VIR_FREE(mask); + xen_vm_set_free(vms); + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virDomainDefPtr defPtr = NULL; + + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) return NULL; + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + if (VIR_ALLOC(defPtr)<0) { + virReportOOMError(); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + memcpy((char *)defPtr->uuid,(char *)dom->uuid,VIR_UUID_BUFLEN); + if (!(defPtr->name = strdup(dom->name))) + goto error_cleanup; + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + if (!(defPtr->os.type = strdup("hvm"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + if(!(defPtr->os.type = strdup("xen"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + if(!(defPtr->os.loader = strdup("pygrub"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.kernel = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.initrd = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.cmdline = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + VIR_FREE(boot_policy); + if(!(defPtr->os.bootloader = strdup("pygrub"))) + goto error_cleanup; + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (STRNEQ(val,"")) { + if(!(defPtr->os.bootloaderArgs = strdup(val))) { + VIR_FREE(val); + goto error_cleanup; + } + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_ACPI); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_APIC); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_PAE); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + xen_vif_set_free(vif_set); + goto error_cleanup; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + xen_vif_set_free(vif_set); + goto error_cleanup; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) + defPtr->nets[i]->data.bridge.brname = bridge; + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + char *xml = virDomainDefFormat(defPtr,0); + virDomainDefFree(defPtr); + return xml; + + error_cleanup: + virReportOOMError(); + xen_vm_set_free(vms); + virDomainDefFree(defPtr); + return NULL; + +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + if (!(usenames = strdup(record->name_label))) { + virReportOOMError(); + xen_vm_record_free(record); + xen_vm_set_free(result); + return -1; + } + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if (createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML"); + virDomainDefFree(defPtr); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (!domP && !(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + virDomainDefFree(defPtr); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + char *result=NULL; + if (!(result = strdup("credit"))) + virReportOOMError(); + return result; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_host_metrics_get_all(session, &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(session, (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information"); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics"); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + NULL, /* domainXmlFromNative */ + NULL, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, + NULL, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + NULL, /* domainGetSchedulerParameters */ + NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ + NULL, + NULL, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + NULL, /* nodeDeviceDettach */ + NULL, /* nodeDeviceReAttach */ + NULL, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, SSL_flag); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, SSL_flag); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c_bak ./libvirt/src/xenapi/xenapi_driver.c_bak --- ./libvirt_org/src/xenapi/xenapi_driver.c_bak 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c_bak 2010-02-22 11:34:01.000000000 +0000 @@ -0,0 +1,1774 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password( call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + privP = malloc(sizeof(struct _xenapiPrivate)); + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + *hvVer = 1; + return 0; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +} + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + createVMRecordFromXml( conn, xmlDesc, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup(result->contents[i].val); + } else { + os_version = strdup("linux"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + virBufferAddLit(&buf, "<domain type='xenapi'>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", "testVM"); + virUUIDFormat(dom->uuid,uuid_string); + virBufferEscapeString(&buf, " <uuid>%s</uuid>\n",uuid_string); + + + virBufferAddLit(&buf, " <os>\n"); + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + virBufferAddLit(&buf, " <type>hvm</type>\n"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int j=0; + while(result->contents[i].val[j]!='\0') { + virBufferEscapeString(&buf, " <boot dev='%s' />\n", + mapXmlBootOrder(result->contents[i].val[j])); + j++; + } + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + virBufferAddLit(&buf, " <type>linux</type>\n"); + virBufferAddLit(&buf, " <loader>pygrub</loader>\n"); + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <kernel>%s</kernel>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <initrd>%s</initrd>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <cmdline>%s</cmdline>\n",value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + } + virBufferAddLit(&buf, " </os>\n"); + virBufferAddLit(&buf, " <bootloader>pygrub</bootloader>\n"); + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + virBufferEscapeString(&buf," <bootloader_args>%s</bootloader_args>\n",val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + virBufferVSprintf(&buf," <memory>%lu</memory>\n",memory); + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + virBufferVSprintf(&buf," <currentmemory>%lld</currentmemory>\n",(dynamic_mem/1024)); + } else { + virBufferVSprintf(&buf," <currentmemory>%lu</currentmemory>\n",memory); + } + virBufferVSprintf(&buf," <vcpu>%d</vcpu>\n",xenapiDomainGetMaxVcpus(dom)); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_poweroff>%s</on_poweroff>\n",xen_on_normal_exit_to_string(action)); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_reboot>%s</on_reboot>\n",xen_on_normal_exit_to_string(action)); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + virBufferEscapeString(&buf," <on_crash>%s</on_crash>\n",xen_on_crash_behaviour_to_string(crash)); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + virBufferAddLit(&buf, " <features>\n"); + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + virBufferVSprintf(&buf," <%s/>\n",result->contents[i].key); + } + } + virBufferAddLit(&buf, " </features>\n"); + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + for (i=0; i<vif_set->size; i++) { + virBufferAddLit(&buf, " <interface type='bridge'>\n"); + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + virBufferEscapeString(&buf," <source bridge='%s' />\n",bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + xen_vif_record_free(vif_rec); + } + virBufferAddLit(&buf, " </interface>\n"); + } + xen_vif_set_free(vif_set); + } + virBufferAddLit(&buf, "</domain>"); + if (vms) xen_vm_set_free(vms); + return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + if(createVMRecordFromXml( conn, xml, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c_mod ./libvirt/src/xenapi/xenapi_driver.c_mod --- ./libvirt_org/src/xenapi/xenapi_driver.c_mod 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c_mod 2010-02-24 17:10:16.000000000 +0000 @@ -0,0 +1,1878 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "esx/esx_util.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + //char *pwd = esxUtil_RequestPassword(auth,user,conn->uri->server); + //fprintf(stderr,"pwd:%s",pwd); + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + //privP = malloc(sizeof(struct _xenapiPrivate)); + if (VIR_ALLOC(privP)<0) + return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + xen_string_string_map *result=NULL; + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val); + } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release); + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virCapsPtr +getCapsObject() +{ + virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64"); + caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen"); + return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ +/* virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +*/ + virCapsPtr caps = getCapsObject(conn); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps); + VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup("hvm"); + } else { + os_version = strdup("xen"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL; + if (VIR_ALLOC(defPtr)<0) + return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + fprintf(stderr,"\nname:%s",defPtr->name); + defPtr->id = dom->id; + strcpy(defPtr->uuid,dom->uuid); + defPtr->name = strdup(dom->name); + + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + //virBufferEscapeString(&buf, " <boot dev='%s' />\n", + // mapXmlBootOrder(result->contents[i].val[j])); + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + fprintf(stderr,"\ncnt:%d",cnt); + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux"); + defPtr->os.loader = strdup("pygrub"); + + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub"); + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + fprintf(stderr,"\nactions after shutdown:%d",action); + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + fprintf(stderr,"\nactions after reboot:%d",action); + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + fprintf(stderr,"\nactions after crash:%d",action); + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + fprintf(stderr,"\nVIR_ALLOC_N"); + return NULL; + } + fprintf(stderr,"\ndump 1"); + //defPtr->nnets = (virDomainNetDefPtr *)malloc(sizeof(virDomainNetDefPtr)*vif_set->size); + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + fprintf(stderr,"\nVIR_ALLOC"); + return NULL; + } + fprintf(stderr,"\ndump 2"); + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + //virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0); + //return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-26 13:21:50.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_PRIV_H__ +#define __VIR_XENAPI_PRIV_H__ + + +extern int xenapiRegister (void); + + +#endif /* __VIR_XENAPI_PRIV_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-03-03 10:57:17.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> +#include "virterror_internal.h" + +//#define PRINT_XML +#define VIR_FROM_THIS VIR_FROM_XENAPI +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; + virCapsPtr caps; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-03-03 14:15:06.000000000 +0000 @@ -0,0 +1,531 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "domain_conf.h" +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" +#include "util/logging.h" + + + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname) +{ + unsigned int ncred; + virConnectCredential cred; + char *prompt; + + memset(&cred, 0, sizeof(virConnectCredential)); + + if (virAsprintf(&prompt, "Enter %s password for %s", username, + hostname) < 0) { + return NULL; + } + + for (ncred = 0; ncred < auth->ncredtype; ncred++) { + if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE && + auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) { + continue; + } + + cred.type = auth->credtype[ncred]; + cred.prompt = prompt; + cred.challenge = hostname; + cred.defresult = NULL; + cred.result = NULL; + cred.resultlen = 0; + + if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) { + VIR_FREE(cred.result); + } + + break; + } + + VIR_FREE(prompt); + + return cred.result; +} + + + + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_normal_exit num = XEN_ON_NORMAL_EXIT_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_NORMAL_EXIT_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_NORMAL_EXIT_RESTART; + return num; +} + + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_crash_behaviour num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_CRASH_BEHAVIOUR_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + else if (action == VIR_DOMAIN_LIFECYCLE_PRESERVE) + num = XEN_ON_CRASH_BEHAVIOUR_PRESERVE; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART_RENAME) + num = XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART; + return num; +} + +/* generate XenAPI boot order format from libvirt format */ +char * +createXenAPIBootOrderString(int nboot, int *bootDevs) +{ + virBuffer ret = VIR_BUFFER_INITIALIZER; + char *val = NULL; + int i; + for (i=0;i<nboot;i++) { + if (bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) + val = (char *)"a"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_DISK) + val = (char *)"c"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) + val = (char *)"d"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_NET) + val = (char *)"n"; + if (val) + virBufferEscapeString(&ret,"%s",val); + } + return virBufferContentAndReset(&ret); +} + +/* convert boot order string to libvirt boot order enum */ +enum virDomainBootOrder +map2LibvirtBootOrder(char c) { + switch(c) { + case 'a': + return VIR_DOMAIN_BOOT_FLOPPY; + case 'c': + return VIR_DOMAIN_BOOT_DISK; + case 'd': + return VIR_DOMAIN_BOOT_CDROM; + case 'n': + return VIR_DOMAIN_BOOT_NET; + default: + return -1; + } +} + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_NORMAL_EXIT_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_NORMAL_EXIT_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + return num; +} + + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_CRASH_BEHAVIOUR_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + else if (action == XEN_ON_CRASH_BEHAVIOUR_PRESERVE) + num = VIR_DOMAIN_LIFECYCLE_PRESERVE; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART_RENAME; + return num; +} + + + +/* returns 'file' or 'block' for the storage type */ +int +getStorageVolumeType(char *type) +{ + if((STREQ(type,"lvmoiscsi")) || + (STREQ(type,"lvmohba")) || + (STREQ(type,"lvm")) || + (STREQ(type,"file")) || + (STREQ(type,"iso")) || + (STREQ(type,"ext")) || + (STREQ(type,"nfs"))) + return (int)VIR_STORAGE_VOL_FILE; + else if((STREQ(type,"iscsi")) || + (STREQ(type,"equal")) || + (STREQ(type,"hba")) || + (STREQ(type,"cslg")) || + (STREQ(type,"udev")) || + (STREQ(type,"netapp"))) + return (int)VIR_STORAGE_VOL_BLOCK; + return -1; +} + +/* returns error description if any received from the server */ +char * +returnErrorFromSession(xen_session *session) +{ + int i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + for (i=0; i<session->error_description_count-1; i++) { + if (!i) + virBufferEscapeString(&buf,"%s",session->error_description[i]); + else + virBufferEscapeString(&buf," : %s",session->error_description[i]); + } + return virBufferContentAndReset(&buf); +} + +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + //virBuffer buf = VIR_BUFFER_INITIALIZER; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + //virBufferVSprintf(&buf,"%d,", (8*i)+j); + strcat(mapstr, buf); + } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr); + //virBufferContentAndReset(&buf); + return ret; +} + +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL,*bp=NULL; + bzero(cpumap, maplen); + num = strtok_r (mask, ",", &bp); + while (num != NULL) { + if (sscanf (num, "%d", &pos)!=1) + virReportOOMError(); + if (pos<0 || pos>max_bits-1) + VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok_r (NULL, ",", &bp); + } +} + + +/* mapping XenServer power state to Libvirt power state */ +virDomainState +mapPowerState(enum xen_vm_power_state state) +{ + virDomainState virState; + switch (state) { + case (XEN_VM_POWER_STATE_HALTED): + case (XEN_VM_POWER_STATE_SUSPENDED): + virState = VIR_DOMAIN_SHUTOFF; + break; + case (XEN_VM_POWER_STATE_PAUSED): + virState = VIR_DOMAIN_PAUSED; + break; + case (XEN_VM_POWER_STATE_RUNNING): + virState = VIR_DOMAIN_RUNNING; + break; + case (XEN_VM_POWER_STATE_UNKNOWN): + case (XEN_VM_POWER_STATE_UNDEFINED): + virState = VIR_DOMAIN_NOSTATE; + break; + default: + virState = VIR_DOMAIN_NOSTATE; + break; + } + return virState; +} + +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) { + virReportOOMError(); + return -1; + } + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val); + return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} + +/* creates network intereface for VM */ +int +createVifNetwork (virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac) +{ + xen_vm xvm = NULL; + char *uuid = NULL; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, vm); + if (uuid) { + if(!xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &xvm, uuid)) + return -1; + VIR_FREE(uuid); + } + xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc(); + vm_opt->is_record = 0; + vm_opt->u.handle = xvm; + xen_network_set *net_set = NULL; + xen_network_record *net_rec = NULL; + int cnt=0; + if (xen_network_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &net_set)) { + for(cnt=0;cnt<(net_set->size);cnt++) { + if (xen_network_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &net_rec, net_set->contents[cnt])) { + if (STREQ(net_rec->bridge,bridge)) { + break; + } else { + xen_network_record_free(net_rec); + } + } + } + } + if ( (cnt<net_set->size) && net_rec) { + xen_network network = NULL; + xen_network_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &network, net_rec->uuid); + xen_network_record_opt *network_opt = xen_network_record_opt_alloc(); + network_opt->is_record = 0; + network_opt->u.handle = network; + xen_vif_record *vif_record = xen_vif_record_alloc(); + vif_record->mac = mac; + vif_record->vm = vm_opt; + vif_record->network = network_opt; + xen_vif vif=NULL; + + vif_record->other_config = xen_string_string_map_alloc(0); + vif_record->runtime_properties = xen_string_string_map_alloc(0); + vif_record->qos_algorithm_params = xen_string_string_map_alloc(0); + vif_record->device = strdup(device); + xen_vif_create(((struct _xenapiPrivate *)(conn->privateData))->session, + &vif, vif_record); + if (!vif) { + xen_vif_free(vif); + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + xen_network_set_free(net_set); + return 0; + } + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + } + if (net_set!=NULL) xen_network_set_free(net_set); + return -1; +} + +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + char uuidStr[VIR_UUID_STRING_BUFLEN]; + *record = xen_vm_record_alloc(); + if (!((*record)->name_label = strdup(def->name))) + goto error_cleanup; + if (def->uuid) { + virUUIDFormat(def->uuid,uuidStr); + if (!((*record)->uuid = strdup(uuidStr))) + goto error_cleanup; + } + if (STREQ(def->os.type,"hvm")) { + if(!((*record)->hvm_boot_policy = strdup("BIOS order"))) + goto error_cleanup; + char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + if (!((*record)->pv_bootloader = strdup("pygrub"))) + goto error_cleanup; + if (def->os.kernel){ + if (!((*record)->pv_kernel = strdup(def->os.kernel))) + goto error_cleanup; + } + if (def->os.initrd) { + if (!((*record)->pv_ramdisk = strdup(def->os.initrd))) + goto error_cleanup; + } + if(def->os.cmdline) { + if (!((*record)->pv_args = strdup(def->os.cmdline))) + goto error_cleanup; + } + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + if(!((*record)->pv_bootloader_args = strdup(def->os.bootloaderArgs))) + goto error_cleanup; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<VIR_DOMAIN_FEATURE_ACPI)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_APIC)) + allocStringMap(&strings,(char *)"apic",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_PAE)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + } + if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + if(!(bridge = strdup(def->nets[i]->data.bridge.brname))) + goto error_cleanup; + if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + if(!(mac = strdup(macStr))) { + if (bridge) VIR_FREE(bridge); + goto error_cleanup; + } + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + } + if (bridge) VIR_FREE(bridge); + /*if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + if (createVifNetwork(conn, *vm, device, bridge, mac)<0) { + VIR_FREE(mac); + VIR_FREE(bridge); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + VIR_FREE(bridge); + device_number++; + } else { + if (bridge) + VIR_FREE(bridge); + if (mac) + VIR_FREE(mac); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + }*/ + } + } + return 0; + + error_cleanup: + virReportOOMError(); + xen_vm_record_free(*record); + return -1; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-03-02 13:49:06.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#ifndef _VIR_XENAPI_UTILS_ +#define _VIR_XENAPI_UTILS_ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "conf/domain_conf.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" + +#define NETWORK_DEVID_SIZE (10) + +typedef uint64_t cpumap_t; + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname); + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +char * +createXenAPIBootOrderString(int nboot, int *bootDevs); + +enum virDomainBootOrder map2LibvirtBootOrder(char c); + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action); + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action); + +void getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen); + +int getStorageVolumeType(char *type); + +char *returnErrorFromSession(xen_session *session); + +virDomainState +mapPowerState(enum xen_vm_power_state state); + +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen); + +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr defPtr, + xen_vm_record **record, xen_vm *vm); + +int +allocStringMap (xen_string_string_map **strings, char *key, char *val); + +int +createVifNetwork(virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac); + +#endif //_VIR_XENAPI_UTILS_ -----Original Message----- From: Matthias Bolte [mailto:matthias.bolte@googlemail.com] Sent: 26 February 2010 20:00 To: Sharadha Prabhakar (3P) Cc: libvir-list@redhat.com; Ewan Mellor Subject: Re: [libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt 2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
This patch contains XenAPI driver specific files. Files included are xenapi_driver.c xenapi_utils.c xenapi_driver.h xenapi_driver_private.h xenapi_utils.h This patch includes changes suggested in the first review.
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ +
+ +char *url=NULL;
You should move this into the xenapiPrivate struct, otherwise you'll have trouble using multiple XenAPI connections at the same time, because multiple calls to xenapiOpen will overwrite the pointer an leak the previous value.
+/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_ERROR;
If the URI is not for you (scheme != XenAPI) then you must decline it (return VIR_DRV_OPEN_DECLINED) and not return VIR_DRV_OPEN_ERROR. All other schemes in libvirt are lowercase. I suggest you change it to "xenapi" or switch the STREQ to STRCASEEQ to do a case-insensitive comparison.
+ } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = esxUtil_RequestPassword(auth,conn->uri->user,conn->uri->server);
You cannot use ESX driver code here, because inter-driver dependencies are forbidden. So we could either move this function into the src/utils/utils.c or you duplicate the function in the XenAPI driver code. I suggest the later because esxUtil_RequestPassword's behavior is special for the ESX driver (setting the challenge to the hostname).
+ } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + virAsprintf(&url,"https://%s",conn->uri->server);
You should check the return value from virAsprintf and report an OOM error if the return value is negative.
+ xmlInitParser(); + xmlKeepBlanksDefault(0);
I'm not sure if it's a good idea to change global libxml2 defaults. I can't tell if this is the default anyway, or if it'll will affect the other XML parsing code in libvirt in a negative way, because the libxml2 documentation for this function is confusing to me.
+ xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, conn->uri->user, passwd, xen_api_latest_version); + + if ( session && session->ok ) { + if (VIR_ALLOC(privP)<0)
You need to call virReportOOMError() here, to report the allocation failure.
+ return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + return VIR_DRV_OPEN_ERROR; + } +} +
+ +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} +
+ +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
Remove ATTRIBUTE_UNUSED from conn, as conn is used in this function.
+{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return -1; + } + xen_string_string_map *result=NULL;
You should define new variables always at the beginning of a block.
+ if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val);
You need to check the return value strdup of for NULL and report an OOM error using virReportOOMError if it's NULL. Also you need to break the for loop if you found the version string, otherwise you may strdup and assign a string multiple times to version and leak the previous allocated memeory.
+ } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release);
You should check the return value of sscanf to see if it failed.
+ *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} +
+ +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2);
You should use virStrncpy here and check its return value.
+ info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +static virCapsPtr +getCapsObject(void) +{
You're not supposed to build the caps structure by hand. Use the virCapabilities* functions.
+ virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64");
Use virCapabilitiesNew instead.
+ caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen");
Use virCapabilitiesAddGuest and virCapabilitiesAddGuestDomain instead.
+ return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virCapsPtr caps = getCapsObject(); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps);
You could improve this by creating the caps once per connection and store the virCapsPtr in the xenapiPrivate struct, instead of recreating it over and over again.
+ VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size;
That's wrong. Assume the case that result->size is greater than maxids, then you are reporting back more IDs than you actually wrote to the ids array.
+ xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid);
createVMRecordFromXml doesn't copy the UUID from the virDomainDefPtr to the xen_vm_record, so parsing it here gives wrong results.
+ if (vm!=NULL) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid);
You forgot to set the domain ID (domP->id).
+ xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
You're leaking the caps object here.
+ return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record);
You should break the for loop if the domain id found.
+ } + }
You should report an error if the domain is not found.
+ xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_uuid(session, &vm, (char *)uuid)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid);
const unsigned char *uuid is already in raw format. Parsing it again will give wrong results. Did you actually test this function?
+ domP = virGetDomain(conn, record->name_label, raw_uuid);
The domain ID should be set here.
+ xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} +
+ +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + }
Is vms->contents[0] guaranteed to be valid if xen_vm_get_by_name_label succeeds?
+ vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Okay you check vms->size here before accessing vms->contents[0]. So you should do the same in xenapiDomainSuspend.
+ if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
vms->size check missing here as in xenapiDomainSuspend.
+ vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} +
+ +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) {
Is distro != windows a good indicator for paravirtualization mode? How do you detect the case when you have a non-windows system in HVM mode?
+ os_version = strdup("hvm");
OOM check missing.
+ } else { + os_version = strdup("xen");
OOM check missing.
+ } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + if ( os_version == NULL ) { + os_version = strdup("unknown");
OOM check missing.
+ } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms != NULL && vms->size!=0) {
Maybe you should unify the way you check for a valid vm set, because you do it both ways around.
+ /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} +
+ +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
You forget to check for a valid vm set.
+ vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +
+ +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen);
value leaks.
+ xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) return -1;
You call should call virReportOOMError in case of an allcoation error.
+ if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Check for a valid vm set is missing.
+ vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val);
Break the for look here an check for OOM error here.
+ } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + }
mask leaks.
+ return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
Check for a valid vm set is missing.
+ vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL;
Use virDomainDefPtr.
+ if (VIR_ALLOC(defPtr)<0)
virReportOOMError missing.
+ return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + strcpy((char *)defPtr->uuid,(char *)dom->uuid);
You cannot copy a raw UUID using strcpy, becaue it isn't a string an can contain 0 values. But strcpy will stop at the first 0 value. Use memcpy(defPtr->uuid, dom->uuid, VIR_UUID_BUFLEN) instead.
+ defPtr->name = strdup(dom->name);
OOM check missing.
+ char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm");
OOM check missing.
+ xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux");
Use xen instead of linux.
+ defPtr->os.loader = strdup("pygrub");
OOM checks missing.
+ + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub");
OOM check missing.
+ } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val);
OOM check missing. Also use STRNEQ instead of !STREQ.
+ VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0);
Use VIR_DOMAIN_FEATURE_ACPI instead of 0.
+ else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1);
Use VIR_DOMAIN_FEATURE_APIC instead of 1.
+ else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2);
Use VIR_DOMAIN_FEATURE_PAE instead of 2.
+ } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) {
virReportOOMError missing.
+ return NULL; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) {
virReportOOMError missing.
+ return NULL; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge);
Why strdup'ing and freeing bridge? Why not assign it directly?
+ } + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0);
You're leaking defPtr here. Free it using virDomainDefFree.
+} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label);
OOM check missing.
+ names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL);
You're abusing VIR_ERR_NO_DEVICE here.
+ return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL);
You're abusing VIR_ERR_NO_DEVICE here.
+ return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else {
You're potentially leaking vms here, because if vms is not NULL but vms->size is then you goto the else branch and vms leaks. I just noticed this pattern here, but this affects probably several functions.
+ xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML");
You're leaking defPtr here. Free it using virDomainDefFree.
+ return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm);
You're leaking defPtr here. Free it using virDomainDefFree.
+ return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Again, missing check for a valid vm set.
+ vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Missing check for a valid vm set.
+ vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Missing check for a valid vm set.
+ vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit";
Don't return a const string here. The result is suppoed to be allocated. You need to strdup it and don't forget the OOM check.
+} +
+ +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells)
Remove ATTRIBUTE_UNUSED from freeMems.
+{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} +
+ +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
You should set CURLOPT_SSL_VERIFYHOST to 2, with 1 the common name field is ignored. Or just don't change the SSL config. libcurl defaults to secure settings.
+ CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} +
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-02-26 15:15:55.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> + +#define PRINT_XML +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
+ +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf);
Use the virBuffer API instea of snprintf and strcat.
+ } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr);
Use virAsprintf instead of snprintf and strdup.
+ return ret; +} +
+ +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) + return -1; + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val);
OOM check missing.
+ return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} +
+ +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + *record = xen_vm_record_alloc(); + (*record)->name_label = strdup(def->name);
OOM check missing. As mentioned before, you're forgot to copy the UUID here.
+ if (STREQ(def->os.type,"hvm")) { + (*record)->hvm_boot_policy = strdup("BIOS order");
OOM check missing.
+ char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + (*record)->pv_bootloader = strdup("pygrub");
OOM check missing.
+ (*record)->pv_kernel = def->os.kernel; + (*record)->pv_ramdisk = def->os.initrd; + (*record)->pv_args = def->os.cmdline; + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + (*record)->pv_bootloader_args = def->os.bootloaderArgs; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<0)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<1)) + allocStringMap(&strings,(char *)"apci",(char *)"true"); + if (def->features & (1<<2)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + }
Use the virDomainFeature enum values here too.
+ if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + bridge = strdup(def->nets[i]->data.bridge.brname);
OOM check missing.
+ if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + mac = strdup(macStr);
OOM check missing.
+ } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + }
You need to free bridge here in the case mac is NULL but bridge is not.
+ } + } + return 0; +} +
Matthias

Patch includes 1) global url and SSL flags removed and placed in private driver struct. 2) SSL verify on url parsed using function similar to the one in ESX. 3) mapDomainPinVcpu updated in xenapi_utils.c diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-03-03 18:02:36.000000000 +0000 @@ -0,0 +1,1754 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + + +static virCapsPtr +getCapsObject (void) +{ + virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0); + if (!caps) { + virReportOOMError(); + return NULL; + } + virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0, NULL, NULL, 0, NULL); + if (!guest1) + goto error_cleanup; + virCapsGuestDomainPtr domain1 = virCapabilitiesAddGuestDomain(guest1, "xen", NULL, NULL, 0, NULL); + if (!domain1) + goto error_cleanup; + virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0, NULL, NULL, 0, NULL); + if (!guest2) + goto error_cleanup; + virCapsGuestDomainPtr domain2 = virCapabilitiesAddGuestDomain(guest2, "xen", NULL, NULL, 0, NULL); + if (!domain2) + goto error_cleanup; + + return caps; + + error_cleanup: + virCapabilitiesFree(caps); + return NULL; +} + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd; + xen_session *session; + struct _xenapiPrivate *privP; + int noVerify=0; + + if (!STRCASEEQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_DECLINED; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = xenapiUtil_RequestPassword(auth,conn->uri->user,conn->uri->server); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + if (VIR_ALLOC(privP) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + if (virAsprintf(&(privP->url),"https://%s",conn->uri->server) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + privP->SSLflag=2; + xenapiUtil_ParseQuery(conn, conn->uri,&noVerify); + if (noVerify==1) privP->SSLflag=0; + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, (void *)privP, conn->uri->user, "xenroot", xen_api_latest_version); + + if ( session && session->ok ) { + privP->session = session; + virCapsPtr caps = getCapsObject(); + if (caps) + privP->caps = caps; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + VIR_FREE(privP); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + virCapabilitiesFree(((struct _xenapiPrivate *)(conn->privateData))->caps); + VIR_FREE(((struct _xenapiPrivate *)(conn->privateData))->url); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_string_string_map *result=NULL; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return -1; + } + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for (i=0; i<result->size; i++) { + if (STREQ(result->contents[i].key,"xen")) { + if (!(version = strdup(result->contents[i].val))) { + xen_string_string_map_free(result); + virReportOOMError(); + return -1; + } + break; + } + } + if (version) { + unsigned long major=0,minor=0,release=0; + if (sscanf(version,"%ld.%ld.%ld",&major,&minor,&release)!=3) { + virReportOOMError(); + xen_string_string_map_free(result); + VIR_FREE(version); + return -1; + } + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + //strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + //info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + if (!virStrncpy(info->model,modelname,LIBVIRT_MODELNAME_LEN-1,LIBVIRT_MODELNAME_LEN)){ + virReportOOMError(); + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return -1; + } + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn) +{ + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (caps) { + char *xml = virCapabilitiesFormatXML(caps); + return xml; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Capabilities not available"); + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + + if (result != NULL) { + int i; + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + xen_vm_set_free(result); + return i; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + virDomainDefFree(defPtr); + if (record) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (!domP) { + xen_vm_record_free(record); + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Domain Pointer is invalid"); + return domP; + } + domP->id = record->domid; + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , "Domain Pointer not valid"); + domP = NULL; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + break; + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + char uuidStr[VIR_UUID_STRING_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virUUIDFormat(uuid,uuidStr); + if (xen_vm_get_by_uuid(session, &vm, uuidStr)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + domP = virGetDomain(conn, record->name_label, uuid); + if (!domP) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , "Domain Pointer not valid"); + domP=NULL; + } else { + domP->id = record->domid; + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, (char *)name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + xen_vm_get_uuid(session, &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + } + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + if (!(os_version = strdup("hvm"))) { + virReportOOMError(); + xen_string_string_map_free(result); + xen_vm_record_free(record); + return NULL; + } + break; + } else { + if (!(os_version = strdup("xen"))) { + virReportOOMError(); + xen_string_string_map_free(result); + xen_vm_record_free(record); + return NULL; + } + break; + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return 0; + } + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(session, vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(session, vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu ATTRIBUTE_UNUSED, + unsigned char *cpumap, int maplen) +{ + char *value=NULL; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if ((value = mapDomainPinVcpu(cpumap, maplen))) { + xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + VIR_FREE(value); + return 0; + } + VIR_FREE(value); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) { + virReportOOMError(); + return -1; + } + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) return -1; + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xen_vm_set_free(vms); + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + if (!(mask = strdup(vcpu_params->contents[i].val))){ + xen_vm_set_free(vms); + xen_string_string_map_free(vcpu_params); + virReportOOMError(); + return -1; + } + break; + } + } + xen_string_string_map_free(vcpu_params); + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + VIR_FREE(mask); + xen_vm_set_free(vms); + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virDomainDefPtr defPtr = NULL; + + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) return NULL; + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + if (VIR_ALLOC(defPtr)<0) { + virReportOOMError(); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + memcpy((char *)defPtr->uuid,(char *)dom->uuid,VIR_UUID_BUFLEN); + if (!(defPtr->name = strdup(dom->name))) + goto error_cleanup; + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + if (!(defPtr->os.type = strdup("hvm"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + if(!(defPtr->os.type = strdup("xen"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + if(!(defPtr->os.loader = strdup("pygrub"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.kernel = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.initrd = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.cmdline = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + VIR_FREE(boot_policy); + if(!(defPtr->os.bootloader = strdup("pygrub"))) + goto error_cleanup; + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (STRNEQ(val,"")) { + if(!(defPtr->os.bootloaderArgs = strdup(val))) { + VIR_FREE(val); + goto error_cleanup; + } + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_ACPI); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_APIC); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_PAE); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + xen_vif_set_free(vif_set); + goto error_cleanup; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + xen_vif_set_free(vif_set); + goto error_cleanup; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) + defPtr->nets[i]->data.bridge.brname = bridge; + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + char *xml = virDomainDefFormat(defPtr,0); + virDomainDefFree(defPtr); + return xml; + + error_cleanup: + virReportOOMError(); + xen_vm_set_free(vms); + virDomainDefFree(defPtr); + return NULL; + +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + if (!(usenames = strdup(record->name_label))) { + virReportOOMError(); + xen_vm_record_free(record); + xen_vm_set_free(result); + return -1; + } + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if (createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML"); + virDomainDefFree(defPtr); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (!domP && !(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + virDomainDefFree(defPtr); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + char *result=NULL; + if (!(result = strdup("credit"))) + virReportOOMError(); + return result; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_host_metrics_get_all(session, &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(session, (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information"); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics"); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + NULL, /* domainXmlFromNative */ + NULL, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, + NULL, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + NULL, /* domainGetSchedulerParameters */ + NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ + NULL, + NULL, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + NULL, /* nodeDeviceDettach */ + NULL, /* nodeDeviceReAttach */ + NULL, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + //(void)user_handle; + struct _xenapiPrivate *priv = (struct _xenapiPrivate *)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, priv->url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, priv->SSLflag); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, priv->SSLflag); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; + +} + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c_bak ./libvirt/src/xenapi/xenapi_driver.c_bak --- ./libvirt_org/src/xenapi/xenapi_driver.c_bak 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c_bak 2010-02-22 11:34:01.000000000 +0000 @@ -0,0 +1,1774 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password( call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + privP = malloc(sizeof(struct _xenapiPrivate)); + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + *hvVer = 1; + return 0; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +} + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + createVMRecordFromXml( conn, xmlDesc, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup(result->contents[i].val); + } else { + os_version = strdup("linux"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + virBufferAddLit(&buf, "<domain type='xenapi'>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", "testVM"); + virUUIDFormat(dom->uuid,uuid_string); + virBufferEscapeString(&buf, " <uuid>%s</uuid>\n",uuid_string); + + + virBufferAddLit(&buf, " <os>\n"); + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + virBufferAddLit(&buf, " <type>hvm</type>\n"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int j=0; + while(result->contents[i].val[j]!='\0') { + virBufferEscapeString(&buf, " <boot dev='%s' />\n", + mapXmlBootOrder(result->contents[i].val[j])); + j++; + } + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + virBufferAddLit(&buf, " <type>linux</type>\n"); + virBufferAddLit(&buf, " <loader>pygrub</loader>\n"); + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <kernel>%s</kernel>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <initrd>%s</initrd>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <cmdline>%s</cmdline>\n",value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + } + virBufferAddLit(&buf, " </os>\n"); + virBufferAddLit(&buf, " <bootloader>pygrub</bootloader>\n"); + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + virBufferEscapeString(&buf," <bootloader_args>%s</bootloader_args>\n",val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + virBufferVSprintf(&buf," <memory>%lu</memory>\n",memory); + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + virBufferVSprintf(&buf," <currentmemory>%lld</currentmemory>\n",(dynamic_mem/1024)); + } else { + virBufferVSprintf(&buf," <currentmemory>%lu</currentmemory>\n",memory); + } + virBufferVSprintf(&buf," <vcpu>%d</vcpu>\n",xenapiDomainGetMaxVcpus(dom)); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_poweroff>%s</on_poweroff>\n",xen_on_normal_exit_to_string(action)); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_reboot>%s</on_reboot>\n",xen_on_normal_exit_to_string(action)); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + virBufferEscapeString(&buf," <on_crash>%s</on_crash>\n",xen_on_crash_behaviour_to_string(crash)); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + virBufferAddLit(&buf, " <features>\n"); + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + virBufferVSprintf(&buf," <%s/>\n",result->contents[i].key); + } + } + virBufferAddLit(&buf, " </features>\n"); + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + for (i=0; i<vif_set->size; i++) { + virBufferAddLit(&buf, " <interface type='bridge'>\n"); + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + virBufferEscapeString(&buf," <source bridge='%s' />\n",bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + xen_vif_record_free(vif_rec); + } + virBufferAddLit(&buf, " </interface>\n"); + } + xen_vif_set_free(vif_set); + } + virBufferAddLit(&buf, "</domain>"); + if (vms) xen_vm_set_free(vms); + return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + if(createVMRecordFromXml( conn, xml, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c_mod ./libvirt/src/xenapi/xenapi_driver.c_mod --- ./libvirt_org/src/xenapi/xenapi_driver.c_mod 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c_mod 2010-02-24 17:10:16.000000000 +0000 @@ -0,0 +1,1878 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "esx/esx_util.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + //char *pwd = esxUtil_RequestPassword(auth,user,conn->uri->server); + //fprintf(stderr,"pwd:%s",pwd); + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + //privP = malloc(sizeof(struct _xenapiPrivate)); + if (VIR_ALLOC(privP)<0) + return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + xen_string_string_map *result=NULL; + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val); + } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release); + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virCapsPtr +getCapsObject() +{ + virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64"); + caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen"); + return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ +/* virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +*/ + virCapsPtr caps = getCapsObject(conn); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps); + VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup("hvm"); + } else { + os_version = strdup("xen"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL; + if (VIR_ALLOC(defPtr)<0) + return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + fprintf(stderr,"\nname:%s",defPtr->name); + defPtr->id = dom->id; + strcpy(defPtr->uuid,dom->uuid); + defPtr->name = strdup(dom->name); + + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + //virBufferEscapeString(&buf, " <boot dev='%s' />\n", + // mapXmlBootOrder(result->contents[i].val[j])); + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + fprintf(stderr,"\ncnt:%d",cnt); + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux"); + defPtr->os.loader = strdup("pygrub"); + + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub"); + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + fprintf(stderr,"\nactions after shutdown:%d",action); + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + fprintf(stderr,"\nactions after reboot:%d",action); + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + fprintf(stderr,"\nactions after crash:%d",action); + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + fprintf(stderr,"\nVIR_ALLOC_N"); + return NULL; + } + fprintf(stderr,"\ndump 1"); + //defPtr->nnets = (virDomainNetDefPtr *)malloc(sizeof(virDomainNetDefPtr)*vif_set->size); + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + fprintf(stderr,"\nVIR_ALLOC"); + return NULL; + } + fprintf(stderr,"\ndump 2"); + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + //virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0); + //return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-26 13:21:50.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_PRIV_H__ +#define __VIR_XENAPI_PRIV_H__ + + +extern int xenapiRegister (void); + + +#endif /* __VIR_XENAPI_PRIV_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-03-03 16:09:47.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> +#include "virterror_internal.h" + +//#define PRINT_XML +#define VIR_FROM_THIS VIR_FROM_XENAPI +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; + char *url; + int SSLflag; + virCapsPtr caps; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-03-03 18:01:06.000000000 +0000 @@ -0,0 +1,578 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "domain_conf.h" +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" +#include "util/logging.h" +#include "qparams.h" + + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname) +{ + unsigned int ncred; + virConnectCredential cred; + char *prompt; + + memset(&cred, 0, sizeof(virConnectCredential)); + + if (virAsprintf(&prompt, "Enter %s password for %s", username, + hostname) < 0) { + return NULL; + } + + for (ncred = 0; ncred < auth->ncredtype; ncred++) { + if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE && + auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) { + continue; + } + + cred.type = auth->credtype[ncred]; + cred.prompt = prompt; + cred.challenge = hostname; + cred.defresult = NULL; + cred.result = NULL; + cred.resultlen = 0; + + if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) { + VIR_FREE(cred.result); + } + + break; + } + + VIR_FREE(prompt); + + return cred.result; +} + +int +xenapiUtil_ParseQuery(virConnectPtr conn, xmlURIPtr uri, int *noVerify) +{ + int result = 0; + int i; + struct qparam_set *queryParamSet = NULL; + struct qparam *queryParam = NULL; + +#ifdef HAVE_XMLURI_QUERY_RAW + queryParamSet = qparam_query_parse(uri->query_raw); +#else + queryParamSet = qparam_query_parse(uri->query); +#endif + + if (queryParamSet == NULL) { + goto failure; + } + + for (i = 0; i < queryParamSet->n; i++) { + queryParam = &queryParamSet->p[i]; + if (STRCASEEQ(queryParam->name, "no_verify")) { + if (noVerify == NULL) { + continue; + } + if (virStrToLong_i(queryParam->value, NULL, 10, noVerify) < 0 || + (*noVerify != 0 && *noVerify != 1)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INVALID_ARG, + "Query parameter 'no_verify' has unexpected value (should be 0 or 1)"); + goto failure; + } + } + } + + cleanup: + if (queryParamSet != NULL) { + free_qparam_set(queryParamSet); + } + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_normal_exit num = XEN_ON_NORMAL_EXIT_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_NORMAL_EXIT_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_NORMAL_EXIT_RESTART; + return num; +} + + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_crash_behaviour num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_CRASH_BEHAVIOUR_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + else if (action == VIR_DOMAIN_LIFECYCLE_PRESERVE) + num = XEN_ON_CRASH_BEHAVIOUR_PRESERVE; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART_RENAME) + num = XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART; + return num; +} + +/* generate XenAPI boot order format from libvirt format */ +char * +createXenAPIBootOrderString(int nboot, int *bootDevs) +{ + virBuffer ret = VIR_BUFFER_INITIALIZER; + char *val = NULL; + int i; + for (i=0;i<nboot;i++) { + if (bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) + val = (char *)"a"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_DISK) + val = (char *)"c"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) + val = (char *)"d"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_NET) + val = (char *)"n"; + if (val) + virBufferEscapeString(&ret,"%s",val); + } + return virBufferContentAndReset(&ret); +} + +/* convert boot order string to libvirt boot order enum */ +enum virDomainBootOrder +map2LibvirtBootOrder(char c) { + switch(c) { + case 'a': + return VIR_DOMAIN_BOOT_FLOPPY; + case 'c': + return VIR_DOMAIN_BOOT_DISK; + case 'd': + return VIR_DOMAIN_BOOT_CDROM; + case 'n': + return VIR_DOMAIN_BOOT_NET; + default: + return -1; + } +} + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_NORMAL_EXIT_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_NORMAL_EXIT_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + return num; +} + + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_CRASH_BEHAVIOUR_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + else if (action == XEN_ON_CRASH_BEHAVIOUR_PRESERVE) + num = VIR_DOMAIN_LIFECYCLE_PRESERVE; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART_RENAME; + return num; +} + + + +/* returns 'file' or 'block' for the storage type */ +int +getStorageVolumeType(char *type) +{ + if((STREQ(type,"lvmoiscsi")) || + (STREQ(type,"lvmohba")) || + (STREQ(type,"lvm")) || + (STREQ(type,"file")) || + (STREQ(type,"iso")) || + (STREQ(type,"ext")) || + (STREQ(type,"nfs"))) + return (int)VIR_STORAGE_VOL_FILE; + else if((STREQ(type,"iscsi")) || + (STREQ(type,"equal")) || + (STREQ(type,"hba")) || + (STREQ(type,"cslg")) || + (STREQ(type,"udev")) || + (STREQ(type,"netapp"))) + return (int)VIR_STORAGE_VOL_BLOCK; + return -1; +} + +/* returns error description if any received from the server */ +char * +returnErrorFromSession(xen_session *session) +{ + int i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + for (i=0; i<session->error_description_count-1; i++) { + if (!i) + virBufferEscapeString(&buf,"%s",session->error_description[i]); + else + virBufferEscapeString(&buf," : %s",session->error_description[i]); + } + return virBufferContentAndReset(&buf); +} + +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned char *cpumap, int maplen) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t len; + char *ret=NULL; + int i, j; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + virBufferVSprintf(&buf,"%d,", (8*i)+j); + } + } + } + if (virBufferError(&buf)) { + virReportOOMError(); + virBufferFreeAndReset(&buf); + return NULL; + } + ret = virBufferContentAndReset(&buf); + len = strlen(ret); + if (len > 0 && ret[len - 1] == ',') + ret[len - 1] = 0; + return ret; +} + +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL,*bp=NULL; + bzero(cpumap, maplen); + num = strtok_r (mask, ",", &bp); + while (num != NULL) { + if (sscanf (num, "%d", &pos)!=1) + virReportOOMError(); + if (pos<0 || pos>max_bits-1) + VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok_r (NULL, ",", &bp); + } +} + + +/* mapping XenServer power state to Libvirt power state */ +virDomainState +mapPowerState(enum xen_vm_power_state state) +{ + virDomainState virState; + switch (state) { + case (XEN_VM_POWER_STATE_HALTED): + case (XEN_VM_POWER_STATE_SUSPENDED): + virState = VIR_DOMAIN_SHUTOFF; + break; + case (XEN_VM_POWER_STATE_PAUSED): + virState = VIR_DOMAIN_PAUSED; + break; + case (XEN_VM_POWER_STATE_RUNNING): + virState = VIR_DOMAIN_RUNNING; + break; + case (XEN_VM_POWER_STATE_UNKNOWN): + case (XEN_VM_POWER_STATE_UNDEFINED): + virState = VIR_DOMAIN_NOSTATE; + break; + default: + virState = VIR_DOMAIN_NOSTATE; + break; + } + return virState; +} + +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) { + virReportOOMError(); + return -1; + } + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val); + return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} + +/* creates network intereface for VM */ +int +createVifNetwork (virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac) +{ + xen_vm xvm = NULL; + char *uuid = NULL; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, vm); + if (uuid) { + if(!xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &xvm, uuid)) + return -1; + VIR_FREE(uuid); + } + xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc(); + vm_opt->is_record = 0; + vm_opt->u.handle = xvm; + xen_network_set *net_set = NULL; + xen_network_record *net_rec = NULL; + int cnt=0; + if (xen_network_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &net_set)) { + for(cnt=0;cnt<(net_set->size);cnt++) { + if (xen_network_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &net_rec, net_set->contents[cnt])) { + if (STREQ(net_rec->bridge,bridge)) { + break; + } else { + xen_network_record_free(net_rec); + } + } + } + } + if ( (cnt<net_set->size) && net_rec) { + xen_network network = NULL; + xen_network_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &network, net_rec->uuid); + xen_network_record_opt *network_opt = xen_network_record_opt_alloc(); + network_opt->is_record = 0; + network_opt->u.handle = network; + xen_vif_record *vif_record = xen_vif_record_alloc(); + vif_record->mac = mac; + vif_record->vm = vm_opt; + vif_record->network = network_opt; + xen_vif vif=NULL; + + vif_record->other_config = xen_string_string_map_alloc(0); + vif_record->runtime_properties = xen_string_string_map_alloc(0); + vif_record->qos_algorithm_params = xen_string_string_map_alloc(0); + vif_record->device = strdup(device); + xen_vif_create(((struct _xenapiPrivate *)(conn->privateData))->session, + &vif, vif_record); + if (!vif) { + xen_vif_free(vif); + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + xen_network_set_free(net_set); + return 0; + } + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + } + if (net_set!=NULL) xen_network_set_free(net_set); + return -1; +} + +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + char uuidStr[VIR_UUID_STRING_BUFLEN]; + *record = xen_vm_record_alloc(); + if (!((*record)->name_label = strdup(def->name))) + goto error_cleanup; + if (def->uuid) { + virUUIDFormat(def->uuid,uuidStr); + if (!((*record)->uuid = strdup(uuidStr))) + goto error_cleanup; + } + if (STREQ(def->os.type,"hvm")) { + if(!((*record)->hvm_boot_policy = strdup("BIOS order"))) + goto error_cleanup; + char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + if (!((*record)->pv_bootloader = strdup("pygrub"))) + goto error_cleanup; + if (def->os.kernel){ + if (!((*record)->pv_kernel = strdup(def->os.kernel))) + goto error_cleanup; + } + if (def->os.initrd) { + if (!((*record)->pv_ramdisk = strdup(def->os.initrd))) + goto error_cleanup; + } + if(def->os.cmdline) { + if (!((*record)->pv_args = strdup(def->os.cmdline))) + goto error_cleanup; + } + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + if(!((*record)->pv_bootloader_args = strdup(def->os.bootloaderArgs))) + goto error_cleanup; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<VIR_DOMAIN_FEATURE_ACPI)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_APIC)) + allocStringMap(&strings,(char *)"apic",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_PAE)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + } + if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + if(!(bridge = strdup(def->nets[i]->data.bridge.brname))) + goto error_cleanup; + if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + if(!(mac = strdup(macStr))) { + if (bridge) VIR_FREE(bridge); + goto error_cleanup; + } + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + } + if (bridge) VIR_FREE(bridge); + /*if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + if (createVifNetwork(conn, *vm, device, bridge, mac)<0) { + VIR_FREE(mac); + VIR_FREE(bridge); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + VIR_FREE(bridge); + device_number++; + } else { + if (bridge) + VIR_FREE(bridge); + if (mac) + VIR_FREE(mac); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + }*/ + } + } + return 0; + + error_cleanup: + virReportOOMError(); + xen_vm_record_free(*record); + return -1; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-03-03 18:01:19.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#ifndef _VIR_XENAPI_UTILS_ +#define _VIR_XENAPI_UTILS_ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "conf/domain_conf.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" + +#define NETWORK_DEVID_SIZE (10) + +typedef uint64_t cpumap_t; + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname); + +int +xenapiUtil_ParseQuery(virConnectPtr conn, xmlURIPtr uri, int *noVerify); + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +char * +createXenAPIBootOrderString(int nboot, int *bootDevs); + +enum virDomainBootOrder map2LibvirtBootOrder(char c); + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action); + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action); + +void getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen); + +int getStorageVolumeType(char *type); + +char *returnErrorFromSession(xen_session *session); + +virDomainState +mapPowerState(enum xen_vm_power_state state); + +char * +mapDomainPinVcpu(unsigned char *cpumap, int maplen); + +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr defPtr, + xen_vm_record **record, xen_vm *vm); + +int +allocStringMap (xen_string_string_map **strings, char *key, char *val); + +int +createVifNetwork(virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac); + +#endif //_VIR_XENAPI_UTILS_ -----Original Message----- From: Sharadha Prabhakar (3P) Sent: 03 March 2010 14:29 To: libvir-list@redhat.com Cc: Ewan Mellor; 'Matthias Bolte' Subject: RE: [libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt This patch contains most of the changes suggested by Matthias Bolte. The Uri also supports an optional SSL verification flag. "xenapi://usrname@server?no_verify=1" will disable SSL verification. Could someone review the virDomainGetVcpus and virDomainPinVcpus in particular to ensure that's the implementation libvirt expects out of these APIs. Patch 2/2 is not sent as it contains no changes from the last review. Regards, Sharadha diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-03-03 14:15:41.000000000 +0000 @@ -0,0 +1,1771 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url=NULL; +int SSL_flag = 2; + +static virCapsPtr +getCapsObject (void) +{ + virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0); + if (!caps) { + virReportOOMError(); + return NULL; + } + virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0, NULL, NULL, 0, NULL); + if (!guest1) + goto error_cleanup; + virCapsGuestDomainPtr domain1 = virCapabilitiesAddGuestDomain(guest1, "xen", NULL, NULL, 0, NULL); + if (!domain1) + goto error_cleanup; + virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0, NULL, NULL, 0, NULL); + if (!guest2) + goto error_cleanup; + virCapsGuestDomainPtr domain2 = virCapabilitiesAddGuestDomain(guest2, "xen", NULL, NULL, 0, NULL); + if (!domain2) + goto error_cleanup; + + return caps; + + error_cleanup: + virCapabilitiesFree(caps); + return NULL; +} + +static void +SSLverify(char *uri) +{ + char *tmp=NULL,*str=NULL,*str1=NULL,*str2=NULL; + str1 = strtok_r(uri,"?",&tmp); + if (!str1) return; + str2 = strtok_r(NULL,"?",&tmp); + str = strtok_r(str2,"=",&tmp); + if(!str) return; + str1 = strtok_r(NULL,"=",&tmp); + if(STREQ(str,"no_verify")) { + if(STREQ(str1,"1")) + SSL_flag=0; + } +} + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd,*uri=NULL; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STRCASEEQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_DECLINED; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (virAsprintf(&url,"https://%s",conn->uri->server) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = xenapiUtil_RequestPassword(auth,conn->uri->user,conn->uri->server); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + + if (!(uri=virConnectGetURI(conn))) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , + "Could not get URI: SSL verification flag may be ignored"); + SSLverify(uri); + VIR_FREE(uri); + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, conn->uri->user, "xenroot", xen_api_latest_version); + + if ( session && session->ok ) { + if (VIR_ALLOC(privP) < 0) { + virReportOOMError(); + return VIR_DRV_OPEN_ERROR; + } + privP->session = session; + conn->privateData = privP; + virCapsPtr caps = getCapsObject(); + if (caps) + privP->caps = caps; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + virCapabilitiesFree(((struct _xenapiPrivate *)(conn->privateData))->caps); + VIR_FREE(conn->privateData); + VIR_FREE(url); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_string_string_map *result=NULL; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return -1; + } + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for (i=0; i<result->size; i++) { + if (STREQ(result->contents[i].key,"xen")) { + if (!(version = strdup(result->contents[i].val))) { + xen_string_string_map_free(result); + virReportOOMError(); + return -1; + } + break; + } + } + if (version) { + unsigned long major=0,minor=0,release=0; + if (sscanf(version,"%ld.%ld.%ld",&major,&minor,&release)!=3) { + virReportOOMError(); + xen_string_string_map_free(result); + VIR_FREE(version); + return -1; + } + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + //strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + //info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + if (!virStrncpy(info->model,modelname,LIBVIRT_MODELNAME_LEN-1,LIBVIRT_MODELNAME_LEN)){ + virReportOOMError(); + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return -1; + } + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn) +{ + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (caps) { + char *xml = virCapabilitiesFormatXML(caps); + return xml; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Capabilities not available"); + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + + if (result != NULL) { + int i; + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + xen_vm_set_free(result); + return i; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + virDomainDefFree(defPtr); + if (record) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (!domP) { + xen_vm_record_free(record); + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Domain Pointer is invalid"); + return domP; + } + domP->id = record->domid; + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , "Domain Pointer not valid"); + domP = NULL; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + break; + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + char uuidStr[VIR_UUID_STRING_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virUUIDFormat(uuid,uuidStr); + if (xen_vm_get_by_uuid(session, &vm, uuidStr)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + domP = virGetDomain(conn, record->name_label, uuid); + if (!domP) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR , "Domain Pointer not valid"); + domP=NULL; + } else { + domP->id = record->domid; + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, (char *)name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + xen_vm_get_uuid(session, &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + } + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } else { + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + if (!(os_version = strdup("hvm"))) { + virReportOOMError(); + xen_string_string_map_free(result); + xen_vm_record_free(record); + return NULL; + } + break; + } else { + if (!(os_version = strdup("xen"))) { + virReportOOMError(); + xen_string_string_map_free(result); + xen_vm_record_free(record); + return NULL; + } + break; + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return 0; + } + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(session, vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(session, vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value=NULL; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if ((value = mapDomainPinVcpu(vcpu, cpumap, maplen))) { + xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + VIR_FREE(value); + return 0; + } + VIR_FREE(value); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) { + virReportOOMError(); + return -1; + } + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) return -1; + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xen_vm_set_free(vms); + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + if (!(mask = strdup(vcpu_params->contents[i].val))){ + xen_vm_set_free(vms); + xen_string_string_map_free(vcpu_params); + virReportOOMError(); + return -1; + } + break; + } + } + xen_string_string_map_free(vcpu_params); + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + VIR_FREE(mask); + xen_vm_set_free(vms); + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virDomainDefPtr defPtr = NULL; + + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) return NULL; + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + if (VIR_ALLOC(defPtr)<0) { + virReportOOMError(); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + memcpy((char *)defPtr->uuid,(char *)dom->uuid,VIR_UUID_BUFLEN); + if (!(defPtr->name = strdup(dom->name))) + goto error_cleanup; + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + if (!(defPtr->os.type = strdup("hvm"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + if(!(defPtr->os.type = strdup("xen"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + if(!(defPtr->os.loader = strdup("pygrub"))) { + VIR_FREE(boot_policy); + goto error_cleanup; + } + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.kernel = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.initrd = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (STRNEQ(value,"")) { + if(!(defPtr->os.cmdline = strdup(value))) { + VIR_FREE(boot_policy); + VIR_FREE(value); + goto error_cleanup; + } + VIR_FREE(value); + } + VIR_FREE(boot_policy); + if(!(defPtr->os.bootloader = strdup("pygrub"))) + goto error_cleanup; + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (STRNEQ(val,"")) { + if(!(defPtr->os.bootloaderArgs = strdup(val))) { + VIR_FREE(val); + goto error_cleanup; + } + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_ACPI); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_APIC); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_PAE); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + xen_vif_set_free(vif_set); + goto error_cleanup; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + xen_vif_set_free(vif_set); + goto error_cleanup; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) + defPtr->nets[i]->data.bridge.brname = bridge; + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + char *xml = virDomainDefFormat(defPtr,0); + virDomainDefFree(defPtr); + return xml; + + error_cleanup: + virReportOOMError(); + xen_vm_set_free(vms); + virDomainDefFree(defPtr); + return NULL; + +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + if (!(usenames = strdup(record->name_label))) { + virReportOOMError(); + xen_vm_record_free(record); + xen_vm_set_free(result); + return -1; + } + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) { + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps; + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if (createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML"); + virDomainDefFree(defPtr); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (!domP && !(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + virDomainDefFree(defPtr); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + char *result=NULL; + if (!(result = strdup("credit"))) + virReportOOMError(); + return result; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_host_metrics_get_all(session, &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(session, (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information"); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics"); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + NULL, /* domainXmlFromNative */ + NULL, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, + NULL, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + NULL, /* domainGetSchedulerParameters */ + NULL, /* domainSetSchedulerParameters */ + NULL, /* domainMigratePrepare */ + NULL, /* domainMigratePerform */ + NULL, /* domainMigrateFinish */ + NULL, /* domainBlockStats */ + NULL, /* domainInterfaceStats */ + NULL, + NULL, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + NULL, /* nodeDeviceDettach */ + NULL, /* nodeDeviceReAttach */ + NULL, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, SSL_flag); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, SSL_flag); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c_bak ./libvirt/src/xenapi/xenapi_driver.c_bak --- ./libvirt_org/src/xenapi/xenapi_driver.c_bak 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c_bak 2010-02-22 11:34:01.000000000 +0000 @@ -0,0 +1,1774 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password( call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + privP = malloc(sizeof(struct _xenapiPrivate)); + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + *hvVer = 1; + return 0; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +} + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + createVMRecordFromXml( conn, xmlDesc, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup(result->contents[i].val); + } else { + os_version = strdup("linux"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + virBufferAddLit(&buf, "<domain type='xenapi'>\n"); + virBufferEscapeString(&buf, " <name>%s</name>\n", "testVM"); + virUUIDFormat(dom->uuid,uuid_string); + virBufferEscapeString(&buf, " <uuid>%s</uuid>\n",uuid_string); + + + virBufferAddLit(&buf, " <os>\n"); + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + virBufferAddLit(&buf, " <type>hvm</type>\n"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int j=0; + while(result->contents[i].val[j]!='\0') { + virBufferEscapeString(&buf, " <boot dev='%s' />\n", + mapXmlBootOrder(result->contents[i].val[j])); + j++; + } + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + virBufferAddLit(&buf, " <type>linux</type>\n"); + virBufferAddLit(&buf, " <loader>pygrub</loader>\n"); + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <kernel>%s</kernel>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <initrd>%s</initrd>\n",value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + virBufferEscapeString(&buf," <cmdline>%s</cmdline>\n",value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + } + virBufferAddLit(&buf, " </os>\n"); + virBufferAddLit(&buf, " <bootloader>pygrub</bootloader>\n"); + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + virBufferEscapeString(&buf," <bootloader_args>%s</bootloader_args>\n",val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + virBufferVSprintf(&buf," <memory>%lu</memory>\n",memory); + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + virBufferVSprintf(&buf," <currentmemory>%lld</currentmemory>\n",(dynamic_mem/1024)); + } else { + virBufferVSprintf(&buf," <currentmemory>%lu</currentmemory>\n",memory); + } + virBufferVSprintf(&buf," <vcpu>%d</vcpu>\n",xenapiDomainGetMaxVcpus(dom)); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_poweroff>%s</on_poweroff>\n",xen_on_normal_exit_to_string(action)); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + virBufferEscapeString(&buf," <on_reboot>%s</on_reboot>\n",xen_on_normal_exit_to_string(action)); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + virBufferEscapeString(&buf," <on_crash>%s</on_crash>\n",xen_on_crash_behaviour_to_string(crash)); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + virBufferAddLit(&buf, " <features>\n"); + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + virBufferVSprintf(&buf," <%s/>\n",result->contents[i].key); + } + } + virBufferAddLit(&buf, " </features>\n"); + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + for (i=0; i<vif_set->size; i++) { + virBufferAddLit(&buf, " <interface type='bridge'>\n"); + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + virBufferEscapeString(&buf," <source bridge='%s' />\n",bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + xen_vif_record_free(vif_rec); + } + virBufferAddLit(&buf, " </interface>\n"); + } + xen_vif_set_free(vif_set); + } + virBufferAddLit(&buf, "</domain>"); + if (vms) xen_vm_set_free(vms); + return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + if(createVMRecordFromXml( conn, xml, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c_mod ./libvirt/src/xenapi/xenapi_driver.c_mod --- ./libvirt_org/src/xenapi/xenapi_driver.c_mod 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c_mod 2010-02-24 17:10:16.000000000 +0000 @@ -0,0 +1,1878 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "esx/esx_util.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + +char *url; + +/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *user,*passwd; + char delims[]=":"; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user:password@server'", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } + + user = strtok(conn->uri->user,delims); + passwd = strtok(NULL,delims); + + + //char *pwd = esxUtil_RequestPassword(auth,user,conn->uri->server); + //fprintf(stderr,"pwd:%s",pwd); + + url = (char *)malloc(strlen("https://")+strlen(conn->uri->server)+1); + strcpy(url,"https://"); + strcat(url,conn->uri->server); + url[strlen("https://")+strlen(conn->uri->server)]='\0'; + + xmlInitParser(); + xmlKeepBlanksDefault(0); + xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, user, passwd, xen_api_latest_version); + + if ( session != NULL && session->ok ) { + //privP = malloc(sizeof(struct _xenapiPrivate)); + if (VIR_ALLOC(privP)<0) + return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"", __FILE__, __FUNCTION__, __LINE__); + return VIR_DRV_OPEN_ERROR; + } +} + +/* +* xenapiClose: +* +* Returns 0 on successful session logout +* +*/ +static int +xenapiClose (virConnectPtr conn) +{ + xen_session_logout(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(conn->privateData); + return 0; +} + +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} + +/* +* xenapiType: +* +* +*Returns name of the driver +*/ +static const char * +xenapiType (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return "XenAPI"; +} + + +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer) +{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + xen_string_string_map *result=NULL; + if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val); + } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release); + *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result; + xen_host host; + + if (!(xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session))) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,"Unable to find host", __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + xen_host_get_hostname(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + return result; +} + + +/* +* xenapiGetMAxVcpus: +* +* +* Returns a hardcoded value for Maximum VCPUS +*/ +static int +xenapiGetMaxVcpus (virConnectPtr conn ATTRIBUTE_UNUSED, const char *type ATTRIBUTE_UNUSED) +{ + /* this is hardcoded for simplicity and set to a resonable value compared + to the actual value */ + return 16; +} + + +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set)) { + xen_host_metrics_get_memory_total(((struct _xenapiPrivate *)(conn->privateData))->session, + &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (xen_host_cpu_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(((struct _xenapiPrivate *)(conn->privateData))->session, + &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2); + info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(((struct _xenapiPrivate *)(conn->privateData))->session, + &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + free(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set", + __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virCapsPtr +getCapsObject() +{ + virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64"); + caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen"); + return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ +/* virBuffer buf = VIR_BUFFER_INITIALIZER; + virBufferAddLit(&buf, "<capabilities>\n"); + virBufferAddLit(&buf, "<host>\n"); + virBufferAddLit(&buf, " <cpu></cpu>\n"); + virBufferAddLit(&buf, "</host>"); + virBufferAddLit(&buf, "<guest>\n"); + virBufferAddLit(&buf, "<os_type>hvm</os_type>\n"); + virBufferAddLit(&buf, "<arch>\n"); + virBufferAddLit(&buf, "<domain type='xenapi'></domain>\n"); + virBufferAddLit(&buf, "</arch>\n"); + virBufferAddLit(&buf, "</guest>\n"); + virBufferAddLit(&buf, "</capabilities>\n"); + return virBufferContentAndReset(&buf); +*/ + virCapsPtr caps = getCapsObject(conn); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps); + VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + if (xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session)) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size; + xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + if (vm!=NULL) { + if (xen_vm_start(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if (host!=NULL && ((struct _xenapiPrivate *)(conn->privateData))->session->ok) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record); + } + } + xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL, __FILE__, __FUNCTION__, __LINE__); + } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &vm, (char *)uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL, __FILE__, __FUNCTION__, __LINE__); + return domP; +} + +/* +* xenapiDomainLookupByName +* +* Returns the domain pointer of domain with matching name +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByName (virConnectPtr conn, + const char *name) +{ + /* vm.get_by_name_label */ + xen_vm_set *vms=NULL; + xen_vm vm; + char *uuid=NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(conn->privateData))->session, + &vms, (char *)name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &uuid, vm); + if (uuid!=NULL) { + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, name, raw_uuid); + if (domP != NULL) { + int64_t domid=-1; + xen_vm_get_domid(((struct _xenapiPrivate *)(conn->privateData))->session, + &domid, vm); + domP->id = domid; + xen_uuid_free(uuid); + xen_vm_set_free(vms); + return domP; + } else { + xen_uuid_free(uuid); + xen_vm_set_free(vms); + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + } + return NULL; + } + } + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + } else { + xenapiSessionErrorHandler(conn,VIR_ERR_NO_DOMAIN,"Domain name not found",__FILE__,__FUNCTION__, __LINE__); + } + return NULL; +} + +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL,__FILE__,__FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_pause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainReboot +* +* Reboots a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainReboot (virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED) +{ + /* vm.clean_reboot */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_clean_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomaindestroy +* +* A VM is hard shutdown +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainDestroy (virDomainPtr dom) +{ + /* vm.hard_shutdown */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_hard_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vm, uuid)) { + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_guest_metrics_get_os_version(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &result, + record->guest_metrics->u.handle); + if (result != NULL) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) { + os_version = strdup("hvm"); + } else { + os_version = strdup("xen"); + } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + if ( os_version == NULL ) { + os_version = strdup("unknown"); + } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms != NULL && vms->size!=0) { + /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return 0; + } +} + +/* +* xenapiDomainSetMaxMemory +* +* Sets maximum static memory for VM on success +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory) +{ + /* vm.set_memory_static_max */ + xen_vm vm; + struct xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!(xen_vm_set_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, memory))) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +static int +xenapiDomainSetMemory (virDomainPtr dom, unsigned long memory ATTRIBUTE_UNUSED) +{ + /* XenAPI doesn't allow this function */ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_memory_static_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSave +* +* suspends a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSave (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED) +{ + int ret_code = -1; + ret_code = xenapiDomainSuspend(dom); + return ret_code; +} + +/* +* xenapiDomainRestore +* +* Resumes a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainRestore (virConnectPtr conn, const char *from ATTRIBUTE_UNUSED) +{ + /* resume from : NI */ + xen_vm_set *result=NULL; + xen_host host=NULL; + xen_vm_record *record = NULL; + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virDomainPtr domP=NULL; + int ret_code=-1; + + xen_session_get_this_host(((struct _xenapiPrivate *)(conn->privateData))->session, &host, + ((struct _xenapiPrivate *)(conn->privateData))->session); + if ( host!=NULL ) { + xen_host_get_resident_vms(((struct _xenapiPrivate *)(conn->privateData))->session, &result, host); + if ( result != NULL ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[0]); + if (record!=NULL) { + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) + ret_code = xenapiDomainResume(domP); + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return ret_code; +} + +static int +xenapiDomainCoreDump (virDomainPtr dom, const char *to ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainSetVcpus +* +* Sets the VCPUs on the domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) +{ + + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (xen_vm_set_vcpus_number_live(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (int64_t)nvcpus)) { + xen_vm_set_free(vms); + return 0; + } + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen); + xen_vm_remove_from_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + domInfo =(struct _virDomainInfo *) malloc(sizeof(struct _virDomainInfo)); + if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + free(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information", + __FILE__, __FUNCTION__, __LINE__); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val); + } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + } + return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + + if (xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + vm = vms->contents[0]; + xen_vm_get_power_state(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL; + if (VIR_ALLOC(defPtr)<0) + return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + fprintf(stderr,"\nname:%s",defPtr->name); + defPtr->id = dom->id; + strcpy(defPtr->uuid,dom->uuid); + defPtr->name = strdup(dom->name); + + char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm"); + xen_vm_get_hvm_boot_params(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + //virBufferEscapeString(&buf, " <boot dev='%s' />\n", + // mapXmlBootOrder(result->contents[i].val[j])); + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + fprintf(stderr,"\ncnt:%d",cnt); + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux"); + defPtr->os.loader = strdup("pygrub"); + + char *value=NULL; + xen_vm_get_pv_kernel(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value); + VIR_FREE(value); + } + xen_vm_get_pv_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value); + VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub"); + } + char *val=NULL; + xen_vm_get_pv_bootloader_args(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val); + VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + fprintf(stderr,"\nactions after shutdown:%d",action); + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &action, vm)) { + fprintf(stderr,"\nactions after reboot:%d",action); + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(((struct _xenapiPrivate *)(dom->conn->privateData))->session, &crash, vm)) { + fprintf(stderr,"\nactions after crash:%d",action); + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0); + else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1); + else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2); + } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) { + fprintf(stderr,"\nVIR_ALLOC_N"); + return NULL; + } + fprintf(stderr,"\ndump 1"); + //defPtr->nnets = (virDomainNetDefPtr *)malloc(sizeof(virDomainNetDefPtr)*vif_set->size); + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) { + fprintf(stderr,"\nVIR_ALLOC"); + return NULL; + } + fprintf(stderr,"\ndump 2"); + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &network, vif); + if (network!=NULL) { + xen_network_get_bridge(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge); + } + xen_network_free(network); + } + xen_vif_get_record(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vif_rec, vif); + if (vif_rec!=NULL) { + //virBufferEscapeString(&buf," <mac address='%s' />\n", vif_rec->mac); + virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0); + //return virBufferContentAndReset(&buf); +} + +static char * +xenapiDomainXMLFromNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *config ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + + +static char * +xenapiDomainXMLToNative(virConnectPtr conn, + const char *format ATTRIBUTE_UNUSED, + const char *xmlData ATTRIBUTE_UNUSED, + unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return NULL; +} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label); + names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record", __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_vm_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &record, result->contents[i]); + if (record==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[RAW_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm); + return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_destroy(((struct _xenapiPrivate *)(dom->conn->privateData))->session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static int +xenapiDomainAttachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainDetachDevice (virDomainPtr dom, const char *xml ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + if(!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + if (!xen_vm_get_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + if (!xen_vm_get_by_name_label(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL, __FILE__, __FUNCTION__, __LINE__); + return -1; + } + vm = vms->contents[0]; + xen_vm_remove_from_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(((struct _xenapiPrivate *)(dom->conn->privateData))->session, + vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL, __FILE__, __FUNCTION__, __LINE__); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit"; +} + +static int +xenapiDomainGetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int *nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainSetSchedulerParameters (virDomainPtr dom, + virSchedParameterPtr params ATTRIBUTE_UNUSED, + int nparams ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePrepare (virConnectPtr dconn, + char **cookie ATTRIBUTE_UNUSED, + int *cookielen ATTRIBUTE_UNUSED, + const char *uri_in ATTRIBUTE_UNUSED, + char **uri_out ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dconn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainMigratePerform (virDomainPtr dom, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED, + const char *dname ATTRIBUTE_UNUSED, + unsigned long resource ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static virDomainPtr +xenapiDomainMigrateFinish (virConnectPtr dconn, + const char *dname, + const char *cookie ATTRIBUTE_UNUSED, + int cookielen ATTRIBUTE_UNUSED, + const char *uri ATTRIBUTE_UNUSED, + unsigned long flags ATTRIBUTE_UNUSED) +{ + return xenapiDomainLookupByName (dconn, dname); +} + +static int +xenapiDomainBlockStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainBlockStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainInterfaceStats (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainBlockPeek (virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, + unsigned long long offset ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED, + void *buffer ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* +* xenapiNodeGetFreeMemory +* +* provides the free memory available on the Node +* Returns memory size on success or 0 in case of error +*/ +static unsigned long long +xenapiNodeGetFreeMemory (virConnectPtr conn) +{ + xen_host_metrics_set *xen_met_set; + unsigned long long freeMem=0; + xen_host_metrics_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, + &xen_met_set); + if (xen_met_set != NULL) { + if (!xen_host_metrics_get_memory_free(((struct _xenapiPrivate *)(conn->privateData))->session, + (int64_t *)&freeMem, xen_met_set->contents[0])) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics - memory information", + __FILE__, __FUNCTION__, __LINE__); + freeMem=0; + } + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get host metrics", + __FILE__, __FUNCTION__, __LINE__); + } + return freeMem; +} + +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells) +{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} + + +static int +xenapiDomainEventRegister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED, + void (*freefunc)(void *) ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiDomainEventDeregister (virConnectPtr conn, + virConnectDomainEventCallback callback ATTRIBUTE_UNUSED) +{ + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceDettach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReAttach (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +static int +xenapiNodeDeviceReset (virNodeDevicePtr dev) +{ + xenapiSessionErrorHandler(dev->conn, VIR_ERR_NO_SUPPORT, "", __FILE__, __FUNCTION__, __LINE__); + return -1; +} + +/* The interface which we export upwards to libvirt.c. */ +static virDriver xenapiDriver = { + VIR_DRV_XENAPI, + "XenAPI", + xenapiOpen, /* open */ + xenapiClose, /* close */ + xenapiSupportsFeature, /* supports_feature */ + xenapiType, /* type */ + xenapiGetVersion, /* version */ + NULL, /*getlibvirtVersion */ + xenapiGetHostname, /* getHostname */ + xenapiGetMaxVcpus, /* getMaxVcpus */ + xenapiNodeGetInfo, /* nodeGetInfo */ + xenapiGetCapabilities, /* getCapabilities */ + xenapiListDomains, /* listDomains */ + xenapiNumOfDomains, /* numOfDomains */ + xenapiDomainCreateXML, /* domainCreateXML */ + xenapiDomainLookupByID, /* domainLookupByID */ + xenapiDomainLookupByUUID, /* domainLookupByUUID */ + xenapiDomainLookupByName, /* domainLookupByName */ + xenapiDomainSuspend, /* domainSuspend */ + xenapiDomainResume, /* domainResume */ + xenapiDomainShutdown, /* domainShutdown */ + xenapiDomainReboot, /* domainReboot */ + xenapiDomainDestroy, /* domainDestroy */ + xenapiDomainGetOSType, /* domainGetOSType */ + xenapiDomainGetMaxMemory, /* domainGetMaxMemory */ + xenapiDomainSetMaxMemory, /* domainSetMaxMemory */ + xenapiDomainSetMemory, /* domainSetMemory */ + xenapiDomainGetInfo, /* domainGetInfo */ + xenapiDomainSave, /* domainSave */ + xenapiDomainRestore, /* domainRestore */ + xenapiDomainCoreDump, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ + NULL, /* domainGetSecurityLabel */ + NULL, /* nodeGetSecurityModel */ + xenapiDomainDumpXML, /* domainDumpXML */ + xenapiDomainXMLFromNative, /* domainXmlFromNative */ + xenapiDomainXMLToNative, /* domainXmlToNative */ + xenapiListDefinedDomains, /* listDefinedDomains */ + xenapiNumOfDefinedDomains, /* numOfDefinedDomains */ + xenapiDomainCreate, /* domainCreate */ + xenapiDomainDefineXML, /* domainDefineXML */ + xenapiDomainUndefine, /* domainUndefine */ + xenapiDomainAttachDevice, /* domainAttachDevice */ + NULL, + xenapiDomainDetachDevice, /* domainDetachDevice */ + NULL, + xenapiDomainGetAutostart, /* domainGetAutostart */ + xenapiDomainSetAutostart, /* domainSetAutostart */ + xenapiDomainGetSchedulerType, /* domainGetSchedulerType */ + xenapiDomainGetSchedulerParameters, /* domainGetSchedulerParameters */ + xenapiDomainSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenapiDomainMigratePrepare, /* domainMigratePrepare */ + xenapiDomainMigratePerform, /* domainMigratePerform */ + xenapiDomainMigrateFinish, /* domainMigrateFinish */ + xenapiDomainBlockStats, /* domainBlockStats */ + xenapiDomainInterfaceStats, /* domainInterfaceStats */ + NULL, + xenapiDomainBlockPeek, /* domainBlockPeek */ + NULL, /* domainMemoryPeek */ + xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + xenapiNodeGetFreeMemory, /* getFreeMemory */ + xenapiDomainEventRegister, /* domainEventRegister */ + xenapiDomainEventDeregister, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ + xenapiNodeDeviceDettach, /* nodeDeviceDettach */ + xenapiNodeDeviceReAttach, /* nodeDeviceReAttach */ + xenapiNodeDeviceReset, /* nodeDeviceReset */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +/** + * xenapiRegister: + * + * + * Returns the driver priority or -1 in case of error. + */ +int +xenapiRegister (void) +{ + return virRegisterDriver (&xenapiDriver); +} + +/* +* write_func +* used by curl to read data from the server +*/ +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms_) +{ + xen_comms *comms = comms_; + size_t n = size * nmemb; + #ifdef PRINT_XML + printf("\n\n---Result from server -----------------------\n"); + printf("%s\n",((char*) ptr)); + fflush(stdout); + #endif + return (size_t) (comms->func(ptr, n, comms->handle) ? n : 0); +} + +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} + + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-26 13:21:50.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_PRIV_H__ +#define __VIR_XENAPI_PRIV_H__ + + +extern int xenapiRegister (void); + + +#endif /* __VIR_XENAPI_PRIV_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-03-03 10:57:17.000000000 +0000 @@ -0,0 +1,47 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> +#include "virterror_internal.h" + +//#define PRINT_XML +#define VIR_FROM_THIS VIR_FROM_XENAPI +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; + virCapsPtr caps; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-03-03 14:15:06.000000000 +0000 @@ -0,0 +1,531 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "domain_conf.h" +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" +#include "util/logging.h" + + + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname) +{ + unsigned int ncred; + virConnectCredential cred; + char *prompt; + + memset(&cred, 0, sizeof(virConnectCredential)); + + if (virAsprintf(&prompt, "Enter %s password for %s", username, + hostname) < 0) { + return NULL; + } + + for (ncred = 0; ncred < auth->ncredtype; ncred++) { + if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE && + auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) { + continue; + } + + cred.type = auth->credtype[ncred]; + cred.prompt = prompt; + cred.challenge = hostname; + cred.defresult = NULL; + cred.result = NULL; + cred.resultlen = 0; + + if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) { + VIR_FREE(cred.result); + } + + break; + } + + VIR_FREE(prompt); + + return cred.result; +} + + + + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_normal_exit num = XEN_ON_NORMAL_EXIT_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_NORMAL_EXIT_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_NORMAL_EXIT_RESTART; + return num; +} + + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_crash_behaviour num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_CRASH_BEHAVIOUR_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + else if (action == VIR_DOMAIN_LIFECYCLE_PRESERVE) + num = XEN_ON_CRASH_BEHAVIOUR_PRESERVE; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART_RENAME) + num = XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART; + return num; +} + +/* generate XenAPI boot order format from libvirt format */ +char * +createXenAPIBootOrderString(int nboot, int *bootDevs) +{ + virBuffer ret = VIR_BUFFER_INITIALIZER; + char *val = NULL; + int i; + for (i=0;i<nboot;i++) { + if (bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) + val = (char *)"a"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_DISK) + val = (char *)"c"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) + val = (char *)"d"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_NET) + val = (char *)"n"; + if (val) + virBufferEscapeString(&ret,"%s",val); + } + return virBufferContentAndReset(&ret); +} + +/* convert boot order string to libvirt boot order enum */ +enum virDomainBootOrder +map2LibvirtBootOrder(char c) { + switch(c) { + case 'a': + return VIR_DOMAIN_BOOT_FLOPPY; + case 'c': + return VIR_DOMAIN_BOOT_DISK; + case 'd': + return VIR_DOMAIN_BOOT_CDROM; + case 'n': + return VIR_DOMAIN_BOOT_NET; + default: + return -1; + } +} + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_NORMAL_EXIT_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_NORMAL_EXIT_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + return num; +} + + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_CRASH_BEHAVIOUR_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + else if (action == XEN_ON_CRASH_BEHAVIOUR_PRESERVE) + num = VIR_DOMAIN_LIFECYCLE_PRESERVE; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART_RENAME; + return num; +} + + + +/* returns 'file' or 'block' for the storage type */ +int +getStorageVolumeType(char *type) +{ + if((STREQ(type,"lvmoiscsi")) || + (STREQ(type,"lvmohba")) || + (STREQ(type,"lvm")) || + (STREQ(type,"file")) || + (STREQ(type,"iso")) || + (STREQ(type,"ext")) || + (STREQ(type,"nfs"))) + return (int)VIR_STORAGE_VOL_FILE; + else if((STREQ(type,"iscsi")) || + (STREQ(type,"equal")) || + (STREQ(type,"hba")) || + (STREQ(type,"cslg")) || + (STREQ(type,"udev")) || + (STREQ(type,"netapp"))) + return (int)VIR_STORAGE_VOL_BLOCK; + return -1; +} + +/* returns error description if any received from the server */ +char * +returnErrorFromSession(xen_session *session) +{ + int i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + for (i=0; i<session->error_description_count-1; i++) { + if (!i) + virBufferEscapeString(&buf,"%s",session->error_description[i]); + else + virBufferEscapeString(&buf," : %s",session->error_description[i]); + } + return virBufferContentAndReset(&buf); +} + +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + //virBuffer buf = VIR_BUFFER_INITIALIZER; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + //virBufferVSprintf(&buf,"%d,", (8*i)+j); + strcat(mapstr, buf); + } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr); + //virBufferContentAndReset(&buf); + return ret; +} + +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL,*bp=NULL; + bzero(cpumap, maplen); + num = strtok_r (mask, ",", &bp); + while (num != NULL) { + if (sscanf (num, "%d", &pos)!=1) + virReportOOMError(); + if (pos<0 || pos>max_bits-1) + VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok_r (NULL, ",", &bp); + } +} + + +/* mapping XenServer power state to Libvirt power state */ +virDomainState +mapPowerState(enum xen_vm_power_state state) +{ + virDomainState virState; + switch (state) { + case (XEN_VM_POWER_STATE_HALTED): + case (XEN_VM_POWER_STATE_SUSPENDED): + virState = VIR_DOMAIN_SHUTOFF; + break; + case (XEN_VM_POWER_STATE_PAUSED): + virState = VIR_DOMAIN_PAUSED; + break; + case (XEN_VM_POWER_STATE_RUNNING): + virState = VIR_DOMAIN_RUNNING; + break; + case (XEN_VM_POWER_STATE_UNKNOWN): + case (XEN_VM_POWER_STATE_UNDEFINED): + virState = VIR_DOMAIN_NOSTATE; + break; + default: + virState = VIR_DOMAIN_NOSTATE; + break; + } + return virState; +} + +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) { + virReportOOMError(); + return -1; + } + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val); + return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} + +/* creates network intereface for VM */ +int +createVifNetwork (virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac) +{ + xen_vm xvm = NULL; + char *uuid = NULL; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, vm); + if (uuid) { + if(!xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &xvm, uuid)) + return -1; + VIR_FREE(uuid); + } + xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc(); + vm_opt->is_record = 0; + vm_opt->u.handle = xvm; + xen_network_set *net_set = NULL; + xen_network_record *net_rec = NULL; + int cnt=0; + if (xen_network_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &net_set)) { + for(cnt=0;cnt<(net_set->size);cnt++) { + if (xen_network_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &net_rec, net_set->contents[cnt])) { + if (STREQ(net_rec->bridge,bridge)) { + break; + } else { + xen_network_record_free(net_rec); + } + } + } + } + if ( (cnt<net_set->size) && net_rec) { + xen_network network = NULL; + xen_network_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &network, net_rec->uuid); + xen_network_record_opt *network_opt = xen_network_record_opt_alloc(); + network_opt->is_record = 0; + network_opt->u.handle = network; + xen_vif_record *vif_record = xen_vif_record_alloc(); + vif_record->mac = mac; + vif_record->vm = vm_opt; + vif_record->network = network_opt; + xen_vif vif=NULL; + + vif_record->other_config = xen_string_string_map_alloc(0); + vif_record->runtime_properties = xen_string_string_map_alloc(0); + vif_record->qos_algorithm_params = xen_string_string_map_alloc(0); + vif_record->device = strdup(device); + xen_vif_create(((struct _xenapiPrivate *)(conn->privateData))->session, + &vif, vif_record); + if (!vif) { + xen_vif_free(vif); + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + xen_network_set_free(net_set); + return 0; + } + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + } + if (net_set!=NULL) xen_network_set_free(net_set); + return -1; +} + +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + char uuidStr[VIR_UUID_STRING_BUFLEN]; + *record = xen_vm_record_alloc(); + if (!((*record)->name_label = strdup(def->name))) + goto error_cleanup; + if (def->uuid) { + virUUIDFormat(def->uuid,uuidStr); + if (!((*record)->uuid = strdup(uuidStr))) + goto error_cleanup; + } + if (STREQ(def->os.type,"hvm")) { + if(!((*record)->hvm_boot_policy = strdup("BIOS order"))) + goto error_cleanup; + char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + if (!((*record)->pv_bootloader = strdup("pygrub"))) + goto error_cleanup; + if (def->os.kernel){ + if (!((*record)->pv_kernel = strdup(def->os.kernel))) + goto error_cleanup; + } + if (def->os.initrd) { + if (!((*record)->pv_ramdisk = strdup(def->os.initrd))) + goto error_cleanup; + } + if(def->os.cmdline) { + if (!((*record)->pv_args = strdup(def->os.cmdline))) + goto error_cleanup; + } + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + if(!((*record)->pv_bootloader_args = strdup(def->os.bootloaderArgs))) + goto error_cleanup; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<VIR_DOMAIN_FEATURE_ACPI)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_APIC)) + allocStringMap(&strings,(char *)"apic",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_PAE)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + } + if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + if(!(bridge = strdup(def->nets[i]->data.bridge.brname))) + goto error_cleanup; + if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + if(!(mac = strdup(macStr))) { + if (bridge) VIR_FREE(bridge); + goto error_cleanup; + } + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + } + if (bridge) VIR_FREE(bridge); + /*if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + if (createVifNetwork(conn, *vm, device, bridge, mac)<0) { + VIR_FREE(mac); + VIR_FREE(bridge); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + VIR_FREE(bridge); + device_number++; + } else { + if (bridge) + VIR_FREE(bridge); + if (mac) + VIR_FREE(mac); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + }*/ + } + } + return 0; + + error_cleanup: + virReportOOMError(); + xen_vm_record_free(*record); + return -1; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-03-02 13:49:06.000000000 +0000 @@ -0,0 +1,90 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#ifndef _VIR_XENAPI_UTILS_ +#define _VIR_XENAPI_UTILS_ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "conf/domain_conf.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" + +#define NETWORK_DEVID_SIZE (10) + +typedef uint64_t cpumap_t; + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname); + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +char * +createXenAPIBootOrderString(int nboot, int *bootDevs); + +enum virDomainBootOrder map2LibvirtBootOrder(char c); + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action); + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action); + +void getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen); + +int getStorageVolumeType(char *type); + +char *returnErrorFromSession(xen_session *session); + +virDomainState +mapPowerState(enum xen_vm_power_state state); + +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen); + +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr defPtr, + xen_vm_record **record, xen_vm *vm); + +int +allocStringMap (xen_string_string_map **strings, char *key, char *val); + +int +createVifNetwork(virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac); + +#endif //_VIR_XENAPI_UTILS_ -----Original Message----- From: Matthias Bolte [mailto:matthias.bolte@googlemail.com] Sent: 26 February 2010 20:00 To: Sharadha Prabhakar (3P) Cc: libvir-list@redhat.com; Ewan Mellor Subject: Re: [libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt 2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
This patch contains XenAPI driver specific files. Files included are xenapi_driver.c xenapi_utils.c xenapi_driver.h xenapi_driver_private.h xenapi_utils.h This patch includes changes suggested in the first review.
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ +
+ +char *url=NULL;
You should move this into the xenapiPrivate struct, otherwise you'll have trouble using multiple XenAPI connections at the same time, because multiple calls to xenapiOpen will overwrite the pointer an leak the previous value.
+/* +*XenapiOpen +* +*Authenticates and creates a session with the server +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR +*/ +static virDrvOpenStatus +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED) +{ + char *passwd; + xen_session *session; + struct _xenapiPrivate *privP; + + if (!STREQ(conn->uri->scheme,"XenAPI")) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'"); + return VIR_DRV_OPEN_ERROR;
If the URI is not for you (scheme != XenAPI) then you must decline it (return VIR_DRV_OPEN_DECLINED) and not return VIR_DRV_OPEN_ERROR. All other schemes in libvirt are lowercase. I suggest you change it to "xenapi" or switch the STREQ to STRCASEEQ to do a case-insensitive comparison.
+ } + if (conn->uri->server==NULL) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI"); + return VIR_DRV_OPEN_ERROR; + } + if (auth) { + passwd = esxUtil_RequestPassword(auth,conn->uri->user,conn->uri->server);
You cannot use ESX driver code here, because inter-driver dependencies are forbidden. So we could either move this function into the src/utils/utils.c or you duplicate the function in the XenAPI driver code. I suggest the later because esxUtil_RequestPassword's behavior is special for the ESX driver (setting the challenge to the hostname).
+ } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found"); + return VIR_DRV_OPEN_ERROR; + } + if (!passwd && !conn->uri->user) { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid"); + return VIR_DRV_OPEN_ERROR; + } + virAsprintf(&url,"https://%s",conn->uri->server);
You should check the return value from virAsprintf and report an OOM error if the return value is negative.
+ xmlInitParser(); + xmlKeepBlanksDefault(0);
I'm not sure if it's a good idea to change global libxml2 defaults. I can't tell if this is the default anyway, or if it'll will affect the other XML parsing code in libvirt in a negative way, because the libxml2 documentation for this function is confusing to me.
+ xen_init(); + curl_global_init(CURL_GLOBAL_ALL); + + session = xen_session_login_with_password (call_func, NULL, conn->uri->user, passwd, xen_api_latest_version); + + if ( session && session->ok ) { + if (VIR_ALLOC(privP)<0)
You need to call virReportOOMError() here, to report the allocation failure.
+ return VIR_DRV_OPEN_ERROR; + privP->session = session; + conn->privateData = privP; + return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + return VIR_DRV_OPEN_ERROR; + } +} +
+ +/* +* +* xenapiSupportsFeature +* +* Returns 0 +*/ +static int +xenapiSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_P2P: + default: + return 0; + } +} +
+ +/* +* xenapiGetVersion: +* +* Gets the version of XenAPI +* +*/ +static int +xenapiGetVersion (virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
Remove ATTRIBUTE_UNUSED from conn, as conn is used in this function.
+{ + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host,session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return -1; + } + xen_string_string_map *result=NULL;
You should define new variables always at the beginning of a block.
+ if (!(xen_host_get_software_version(session, &result, host))) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + xen_host_free(host); + return -1; + } + xen_host_free(host); + if (result && result->size>0) { + int i; + char *version=NULL; + for(i=0;i<result->size;i++) { + if(STREQ(result->contents[i].key,"xen")) + version = strdup(result->contents[i].val);
You need to check the return value strdup of for NULL and report an OOM error using virReportOOMError if it's NULL. Also you need to break the for loop if you found the version string, otherwise you may strdup and assign a string multiple times to version and leak the previous allocated memeory.
+ } + if (version) { + unsigned long major=0,minor=0,release=0; + sscanf(version,"%ld.%ld.%ld",&major,&minor,&release);
You should check the return value of sscanf to see if it failed.
+ *hvVer = major * 1000000 + minor * 1000 + release; + VIR_FREE(version); + xen_string_string_map_free(result); + return 0; + } + } + return -1; +} + + +/* +* xenapiGetHostname: +* +* +* Returns the hostname on success, or NULL on failure +*/ +static char * +xenapiGetHostname (virConnectPtr conn) +{ + char *result=NULL; + xen_host host; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (!(xen_session_get_this_host(session, &host, session))) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return NULL; + } + xen_host_get_hostname(session, &result, host); + xen_host_free(host); + return result; +} +
+ +/* +* xenapiNodeGetInfo: +* +* +* Returns Node details on success or else -1 +*/ +static int +xenapiNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info) +{ + int64_t memory,mhz; + xen_host_cpu_set *host_cpu_set; + xen_host_cpu host_cpu; + xen_host_metrics_set *xen_met_set; + char *modelname; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + info->nodes = 1; + info->threads = 1; + info->sockets = 1; + + if (xen_host_metrics_get_all(session, &xen_met_set)) { + xen_host_metrics_get_memory_total(session, &memory, xen_met_set->contents[0]); + info->memory = (unsigned long)(memory/1024); + xen_host_metrics_set_free(xen_met_set); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get host metric Information"); + return -1; + } + if (xen_host_cpu_get_all(session, &host_cpu_set)) { + host_cpu = host_cpu_set->contents[0]; + xen_host_cpu_get_modelname(session, &modelname, host_cpu); + strncpy(info->model, modelname, LIBVIRT_MODELNAME_LEN-2);
You should use virStrncpy here and check its return value.
+ info->model[LIBVIRT_MODELNAME_LEN-1]='\0'; + xen_host_cpu_get_speed(session, &mhz, host_cpu); + info->mhz = (unsigned long)mhz; + info->cpus = host_cpu_set->size; + info->cores = host_cpu_set->size; + + xen_host_cpu_set_free(host_cpu_set); + VIR_FREE(modelname); + return 0; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Unable to get Host CPU set"); + return -1; +} + +static virCapsPtr +getCapsObject(void) +{
You're not supposed to build the caps structure by hand. Use the virCapabilities* functions.
+ virCapsPtr caps; + if (VIR_ALLOC(caps) < 0) + return NULL; + caps->host.arch = strdup("x86_64");
Use virCapabilitiesNew instead.
+ caps->nguests = 2; + if (VIR_ALLOC_N(caps->guests,2) < 0) + return NULL; + int i; + for (i=0;i<2;i++) { + if (VIR_ALLOC(caps->guests[i]) < 0) + return NULL; + if (VIR_ALLOC_N(caps->guests[i]->arch.domains,1)<0) + return NULL; + if (VIR_ALLOC(caps->guests[i]->arch.domains[0])<0) + return NULL; + caps->guests[i]->arch.name = strdup("x86_64"); + caps->guests[i]->arch.domains[0]->type = strdup("xen"); + caps->guests[i]->arch.ndomains = 1; + } + caps->guests[0]->ostype = strdup("hvm"); + caps->guests[1]->ostype = strdup("xen");
Use virCapabilitiesAddGuest and virCapabilitiesAddGuestDomain instead.
+ return caps; +} + + +/* +* xenapiGetCapabilities: +* +* +* Returns capabilities as an XML string +*/ +static char * +xenapiGetCapabilities (virConnectPtr conn ATTRIBUTE_UNUSED) +{ + virCapsPtr caps = getCapsObject(); + if (caps!=NULL) { + char *xml = virCapabilitiesFormatXML(caps);
You could improve this by creating the caps once per connection and store the virCapsPtr in the xenapiPrivate struct, instead of recreating it over and over again.
+ VIR_FREE(caps); + return xml; + } + return NULL; +} + + +/* +* xenapiListDomains +* +* Collects the list of active domains, and store their ID in @maxids +* Returns the number of domain found or -1 in case of error +*/ +static int +xenapiListDomains (virConnectPtr conn, int *ids, int maxids) +{ + /* vm.list */ + int i,list; + xen_host host; + xen_vm_set *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_session_get_this_host(session, &host, session)) { + xen_host_get_resident_vms(session, &result, host); + xen_host_free(host); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ + if (result != NULL) { + for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) { + int64_t t0; + xen_vm_get_domid(session, &t0, result->contents[i]); + ids[i] = (int)(t0 & 0xffffffff); + } + list = result->size;
That's wrong. Assume the case that result->size is greater than maxids, then you are reporting back more IDs than you actually wrote to the ids array.
+ xen_vm_set_free(result); + return list; + } + return -1; +} + +/* +* xenapiNumOfDomains +* +* +* Returns the number of domains found or -1 in case of error +*/ +static int +xenapiNumOfDomains (virConnectPtr conn) +{ + /* #(vm.list) */ + xen_vm_set *result=NULL; + xen_host host=NULL; + int numDomains=-1; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if ( host!=NULL ) { + xen_host_get_resident_vms(session, &result, host); + if ( result != NULL) { + numDomains = result->size; + xen_vm_set_free(result); + } + xen_host_free(host); + } + if (!(session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ return numDomains; +} + +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + + virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags); + createVMRecordFromXml(conn, defPtr, &record, &vm); + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid);
createVMRecordFromXml doesn't copy the UUID from the virDomainDefPtr to the xen_vm_record, so parsing it here gives wrong results.
+ if (vm!=NULL) { + if (xen_vm_start(session, vm, false, false)) { + domP = virGetDomain(conn, record->name_label, raw_uuid);
You forgot to set the domain ID (domP->id).
+ xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + } + xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
You're leaking the caps object here.
+ return domP; +} + +/* +* xenapiDomainLookupByID +* +* +* Returns a valid domain pointer of the domain with ID same as the one passed +* or NULL in case of error +*/ +static virDomainPtr +xenapiDomainLookupByID (virConnectPtr conn, int id) +{ + int i; + int64_t domID; + char *uuid; + xen_host host; + xen_vm_set *result; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + + xen_session_get_this_host(session, &host, session); + if (host!=NULL && session->ok) { + xen_host_get_resident_vms(session, &result, host); + if ( result !=NULL ) { + for( i=0; i < (result->size); i++) { + xen_vm_get_domid(session, &domID, result->contents[i]); + if ( domID == id ) { + xen_vm_get_record(session, &record, result->contents[i]); + xen_vm_get_uuid(session, &uuid, result->contents[i]); + virUUIDParse(uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP!=NULL) { + int64_t domid=-1; + xen_vm_get_domid(session, &domid, result->contents[i]); + domP->id = domid; + } + xen_uuid_free(uuid); + xen_vm_record_free(record);
You should break the for loop if the domain id found.
+ } + }
You should report an error if the domain is not found.
+ xen_vm_set_free(result); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + } + xen_host_free(host); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE ,NULL);
You're abusing the VIR_ERR_NO_DEVICE error code here.
+ } + return domP; +} + +/* +* xenapiDomainLookupByUUID +* +* Returns the domain pointer of domain with matching UUID +* or -1 in case of error +*/ +static virDomainPtr +xenapiDomainLookupByUUID (virConnectPtr conn, + const unsigned char *uuid) +{ + /* vm.get_by_uuid */ + xen_vm vm; + xen_vm_record *record; + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virDomainPtr domP=NULL; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + if (xen_vm_get_by_uuid(session, &vm, (char *)uuid)) { + xen_vm_get_record(session, &record, vm); + if (record != NULL) { + virUUIDParse((char *)uuid,raw_uuid);
const unsigned char *uuid is already in raw format. Parsing it again will give wrong results. Did you actually test this function?
+ domP = virGetDomain(conn, record->name_label, raw_uuid);
The domain ID should be set here.
+ xen_vm_record_free(record); + } + else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + xen_vm_free(vm); + } else + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN ,NULL); + return domP; +} +
+ +/* +* xenapiDomainSuspend +* +* a VM is paused +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainSuspend (virDomainPtr dom) +{ + /* vm.pause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn,VIR_ERR_NO_DOMAIN,NULL); + return -1; + }
Is vms->contents[0] guaranteed to be valid if xen_vm_get_by_name_label succeeds?
+ vm = vms->contents[0]; + if (!xen_vm_pause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainResume +* +* Resumes a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainResume (virDomainPtr dom) +{ + /* vm.unpause() */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Okay you check vms->size here before accessing vms->contents[0]. So you should do the same in xenapiDomainSuspend.
+ if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_unpause(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } + return 0; +} + +/* +* xenapiDomainShutdown +* +* shutsdown a VM +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainShutdown (virDomainPtr dom) +{ + /* vm.clean_shutdown */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
vms->size check missing here as in xenapiDomainSuspend.
+ vm = vms->contents[0]; + if (!xen_vm_clean_shutdown(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} +
+ +/* +* xenapiDomainGetOSType +* +* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) {
Is distro != windows a good indicator for paravirtualization mode? How do you detect the case when you have a non-windows system in HVM mode?
+ os_version = strdup("hvm");
OOM check missing.
+ } else { + os_version = strdup("xen");
OOM check missing.
+ } + } + } + xen_string_string_map_free(result); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_OS, NULL); + xen_vm_record_free(record); + } else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_free(vm); + } + else + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + if ( os_version == NULL ) { + os_version = strdup("unknown");
OOM check missing.
+ } + return os_version; +} + +/* +* xenapiDomainGetMaxMemory +* +* Returns maximum static memory for VM on success +* or 0 in case of error +*/ +static unsigned long +xenapiDomainGetMaxMemory (virDomainPtr dom) +{ + int64_t mem_static_max=0; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms != NULL && vms->size!=0) {
Maybe you should unify the way you check for a valid vm set, because you do it both ways around.
+ /* vm.get_memory_static_max */ + vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &mem_static_max, vm); + xen_vm_set_free(vms); + return (unsigned long)(mem_static_max/1024); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return 0; + } +} +
+ +/* +* xenapiDomainGetInfo: +* +* Fills a structure with domain information +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) +{ + int64_t maxmem=0,memory=0,vcpu=0; + xen_vm vm; + xen_vm_record *record; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + info->cpuTime = 0; /* CPU time is not advertised */ + if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
You forget to check for a valid vm set.
+ vm = vms->contents[0]; + xen_vm_get_memory_static_max(session, &maxmem, vm); + info->maxMem = (maxmem/1024); + enum xen_vm_power_state state = XEN_VM_POWER_STATE_UNKNOWN; + xen_vm_get_power_state(session, &state, vm); + info->state = mapPowerState(state); + xen_vm_get_record(session, &record, vm); + if (record!=NULL) { + xen_vm_metrics_get_memory_actual(session, &memory, record->metrics->u.handle); + info->memory = (memory/1024); + xen_vm_record_free(record); + } + xen_vm_get_vcpus_max(session, &vcpu, vm); + info->nrVirtCpu = vcpu; + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +
+ +/* +* xenapiDomainPinVcpu +* +* Dynamically change the real CPUs which can be allocated to a virtual CPU +* Returns 0 on success or -1 in case of error +*/ +static int +xenapiDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) +{ + char *value; + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + value = mapDomainPinVcpu(vcpu, cpumap, maplen);
value leaks.
+ xen_vm_remove_from_vcpus_params(session, vm, (char *)"mask"); + if (xen_vm_add_to_vcpus_params(session, vm, (char *)"mask", value)) { + xen_vm_set_free(vms); + return 0; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; +} + +/* +* xenapiDomainGetVcpus +* +* Gets Vcpu information +* Return number of structures filled on success or -1 in case of error +*/ +static int +xenapiDomainGetVcpus (virDomainPtr dom, + virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + + xen_vm_set *vms=NULL; + xen_vm vm=NULL; + xen_string_string_map *vcpu_params=NULL; + int nvcpus=0,cpus=0,i; + virDomainInfoPtr domInfo; + virNodeInfo nodeInfo; + virVcpuInfoPtr ifptr; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + char *mask=NULL; + if((cpumaps!=NULL) && (maplen < 1)) + return -1; + if (VIR_ALLOC(domInfo)<0) return -1;
You call should call virReportOOMError in case of an allcoation error.
+ if (virDomainGetInfo(dom,domInfo)==0) { + nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo); + } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0) + cpus = nodeInfo.cpus; + else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information"); + return -1; + } + if(nvcpus > maxinfo) nvcpus = maxinfo; + + if (cpumaps != NULL) + memset(cpumaps, 0, maxinfo * maplen); + + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Check for a valid vm set is missing.
+ vm = vms->contents[0]; + if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; + } + for (i=0; i<vcpu_params->size; i++) { + if (STREQ(vcpu_params->contents[i].key,"mask")) { + mask = strdup(vcpu_params->contents[i].val);
Break the for look here an check for OOM error here.
+ } + } + for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) { + ifptr->number = i; + ifptr->state = VIR_VCPU_RUNNING; + ifptr->cpuTime = 0; + ifptr->cpu = 0; + if (mask !=NULL) + getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen); + }
mask leaks.
+ return i; +} + +/* +* xenapiDomainGetMaxVcpus +* +* +* Returns maximum number of Vcpus on success or -1 in case of error +*/ +static int +xenapiDomainGetMaxVcpus (virDomainPtr dom) +{ + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu=0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
Check for a valid vm set is missing.
+ vm = vms->contents[0]; + xen_vm_get_power_state(session, &state, vm); + if(state == XEN_VM_POWER_STATE_RUNNING) { + xen_vm_get_vcpus_max(session, &maxvcpu, vm); + } else { + maxvcpu = xenapiGetMaxVcpus(dom->conn, NULL); + } + xen_vm_set_free(vms); + return (int)maxvcpu; + } + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + return -1; +} + +/* +* xenapiDomainDumpXML +* +* +* Returns XML string of the domain configuration on success or -1 in case of error +*/ +static char * +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + xen_string_string_map *result=NULL; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + struct _virDomainDef * defPtr = NULL;
Use virDomainDefPtr.
+ if (VIR_ALLOC(defPtr)<0)
virReportOOMError missing.
+ return NULL; + + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms==NULL || vms->size==0) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; + } + + vm = vms->contents[0]; + defPtr->virtType = VIR_DOMAIN_VIRT_XEN; + defPtr->id = dom->id; + strcpy((char *)defPtr->uuid,(char *)dom->uuid);
You cannot copy a raw UUID using strcpy, becaue it isn't a string an can contain 0 values. But strcpy will stop at the first 0 value. Use memcpy(defPtr->uuid, dom->uuid, VIR_UUID_BUFLEN) instead.
+ defPtr->name = strdup(dom->name);
OOM check missing.
+ char *boot_policy=NULL; + xen_vm_get_hvm_boot_policy(session, &boot_policy, vm); + if (STREQ(boot_policy,"BIOS order")) { + defPtr->os.type = strdup("hvm");
OOM check missing.
+ xen_vm_get_hvm_boot_params(session, &result, vm); + if (result!=NULL) { + int i; + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key,"order")) { + int cnt=0; + while(result->contents[i].val[cnt]!='\0') { + defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]); + cnt++; + } + defPtr->os.nBootDevs = cnt; + } + } + xen_string_string_map_free(result); + } + VIR_FREE(boot_policy); + } else { + defPtr->os.type = strdup("linux");
Use xen instead of linux.
+ defPtr->os.loader = strdup("pygrub");
OOM checks missing.
+ + char *value=NULL; + xen_vm_get_pv_kernel(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.kernel = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + xen_vm_get_pv_ramdisk(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.initrd = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + xen_vm_get_pv_args(session, &value, vm); + if (!STREQ(value,"")) { + defPtr->os.cmdline = strdup(value);
OOM check missing.
+ VIR_FREE(value); + } + VIR_FREE(boot_policy); + defPtr->os.bootloader = strdup("pygrub");
OOM check missing.
+ } + char *val=NULL; + xen_vm_get_pv_bootloader_args(session, &val, vm); + if (!STREQ(val,"")) { + defPtr->os.bootloaderArgs = strdup(val);
OOM check missing. Also use STRNEQ instead of !STREQ.
+ VIR_FREE(val); + } + unsigned long memory=0; + memory = xenapiDomainGetMaxMemory(dom); + defPtr->maxmem = memory; + int64_t dynamic_mem=0; + if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) { + defPtr->memory = (unsigned long) (dynamic_mem/1024); + } else { + defPtr->memory = memory; + } + defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); + } + if (xen_vm_get_actions_after_reboot(session, &action, vm)) { + defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action); + } + enum xen_on_crash_behaviour crash; + if (xen_vm_get_actions_after_crash(session, &crash, vm)) { + defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action); + } + xen_vm_get_platform(session, &result, vm); + if (result!=NULL) { + int i; + for(i=0; i< (result->size); i++) { + if (STREQ(result->contents[i].val,"true")) { + if (STREQ(result->contents[i].key,"acpi")) + defPtr->features = defPtr->features | (1<<0);
Use VIR_DOMAIN_FEATURE_ACPI instead of 0.
+ else if (STREQ(result->contents[i].key,"apic")) + defPtr->features = defPtr->features | (1<<1);
Use VIR_DOMAIN_FEATURE_APIC instead of 1.
+ else if (STREQ(result->contents[i].key,"pae")) + defPtr->features = defPtr->features | (1<<2);
Use VIR_DOMAIN_FEATURE_PAE instead of 2.
+ } + } + xen_string_string_map_free(result); + } + struct xen_vif_set *vif_set=NULL; + xen_vm_get_vifs(session, &vif_set, vm); + if (vif_set) { + int i; + xen_vif vif; + xen_vif_record *vif_rec=NULL; + xen_network network; + char *bridge=NULL; + defPtr->nnets = vif_set->size; + if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) {
virReportOOMError missing.
+ return NULL; + } + for (i=0; i<vif_set->size; i++) { + if (VIR_ALLOC(defPtr->nets[i])<0) {
virReportOOMError missing.
+ return NULL; + } + defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + vif = vif_set->contents[i]; + xen_vif_get_network(session, &network, vif); + if (network!=NULL) { + xen_network_get_bridge(session, &bridge, network); + if (bridge!=NULL) { + defPtr->nets[i]->data.bridge.brname = strdup(bridge); + VIR_FREE(bridge);
Why strdup'ing and freeing bridge? Why not assign it directly?
+ } + xen_network_free(network); + } + xen_vif_get_record(session, &vif_rec, vif); + if (vif_rec!=NULL) { + if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0) + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address"); + xen_vif_record_free(vif_rec); + } + } + xen_vif_set_free(vif_set); + } + if (vms) xen_vm_set_free(vms); + return virDomainDefFormat(defPtr,0);
You're leaking defPtr here. Free it using virDomainDefFree.
+} + +/* +* xenapiListDefinedDomains +* +* list the defined but inactive domains, stores the pointers to the names in @names +* Returns number of names provided in the array or -1 in case of error +*/ +static int +xenapiListDefinedDomains (virConnectPtr conn, char **const names, + int maxnames) +{ + int i,j=0,doms; + xen_vm_set *result; + xen_vm_record *record; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if (result != NULL) { + for (i=0; i< (result->size) && j< maxnames; i++) { + xen_vm_get_record(session, &record, result->contents[i]); + if ( record!=NULL ) { + if ( record->is_a_template == 0 ) { + char *usenames; + usenames = strdup(record->name_label);
OOM check missing.
+ names[j++]=usenames; + } + xen_vm_record_free(record); + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record"); + xen_vm_set_free(result); + return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL);
You're abusing VIR_ERR_NO_DEVICE here.
+ return -1; +} + +/* +* xenapiNumOfDefinedDomains +* +* Provides the number of defined but inactive domains +* Returns number of domains found on success or -1 in case of error +*/ +static int +xenapiNumOfDefinedDomains (virConnectPtr conn) +{ + xen_vm_set *result; + xen_vm_record *record; + int DomNum=0,i; + xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; + xen_vm_get_all(session, &result); + if ( result != NULL) { + for ( i=0; i< (result->size); i++ ) { + xen_vm_get_record(session, &record, result->contents[i]); + if (record==NULL && !session->ok) { + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(result); + return -1; + } + if (record->is_a_template == 0) + DomNum++; + xen_vm_record_free(record); + } + xen_vm_set_free(result); + return DomNum; + } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DEVICE, NULL);
You're abusing VIR_ERR_NO_DEVICE here.
+ return -1; +} + +/* +* xenapiDomainCreate +* +* starts a VM +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainCreate (virDomainPtr dom) +{ + xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + xen_vm_get_by_name_label(session, &vms, dom->name); + if (vms!=NULL && vms->size!=0) { + vm = vms->contents[0]; + if (!xen_vm_start(session, vm, false, false)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + } else {
You're potentially leaking vms here, because if vms is not NULL but vms->size is then you goto the else branch and vms leaks. I just noticed this pattern here, but this affects probably several functions.
+ xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + } + return 0; +} + +/* +* xenapiDomainDefineXML +* +* Defines a domain from the given XML but does not start it +* Returns 0 on success or -1 in case of error +*/ +static virDomainPtr +xenapiDomainDefineXML (virConnectPtr conn, const char *xml) +{ + xen_vm_record *record=NULL; + xen_vm vm=NULL; + virDomainPtr domP=NULL; + virCapsPtr caps = getCapsObject(); + if (!caps) + return NULL; + virDomainDefPtr defPtr = virDomainDefParseString(caps, xml, 0); + if (!defPtr) + return NULL; + if(createVMRecordFromXml( conn, defPtr, &record, &vm)!=0) { + if (!(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + else + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM information from XML");
You're leaking defPtr here. Free it using virDomainDefFree.
+ return NULL; + } + if (record!=NULL) { + unsigned char raw_uuid[VIR_UUID_BUFLEN]; + virUUIDParse(record->uuid,raw_uuid); + domP = virGetDomain(conn, record->name_label, raw_uuid); + if (domP==NULL && !(((struct _xenapiPrivate *)(conn->privateData))->session->ok)) + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + xen_vm_record_free(record); + } + else if (vm!=NULL) + xen_vm_free(vm);
You're leaking defPtr here. Free it using virDomainDefFree.
+ return domP; +} + +/* +* xenapiDomainUndefine +* +* destroys a domain +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainUndefine (virDomainPtr dom) +{ + struct xen_vm_set *vms; + xen_vm vm; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Again, missing check for a valid vm set.
+ vm = vms->contents[0]; + if (!xen_vm_destroy(session, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +/* +* xenapiDomainGetAutostart +* +* Provides a boolean value indicating whether the domain configured +* to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainGetAutostart (virDomainPtr dom, int *autostart) +{ + int i,flag=0; + xen_vm_set *vms; + xen_vm vm; + xen_string_string_map *result; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if(!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Missing check for a valid vm set.
+ vm = vms->contents[0]; + if (!xen_vm_get_other_config(session, &result, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + for (i=0; i < result->size; i++) { + if (STREQ(result->contents[i].key, "auto_poweron")) { + flag=1; + if (STREQ(result->contents[i].val, "true")) + *autostart = 1; + else + *autostart = 0; + } + } + xen_vm_set_free(vms); + xen_string_string_map_free(result); + if (flag==0) return -1; + return 0; +} + +/* +* xenapiDomainSetAutostart +* +* Configure the domain to be automatically started when the host machine boots +* Return 0 on success or -1 in case of error +*/ +static int +xenapiDomainSetAutostart (virDomainPtr dom, int autostart) +{ + xen_vm_set *vms; + xen_vm vm; + char *value; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + if (!xen_vm_get_by_name_label(session, &vms, dom->name)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL); + return -1; + }
Missing check for a valid vm set.
+ vm = vms->contents[0]; + xen_vm_remove_from_other_config(session, vm, (char *)"auto_poweron"); + if (autostart==1) + value = (char *)"true"; + else + value = (char *)"false"; + if (!xen_vm_add_to_other_config(session, vm, (char *)"auto_poweron", value)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + xen_vm_set_free(vms); + return -1; + } + xen_vm_set_free(vms); + return 0; +} + +static char * +xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams) +{ + *nparams = 0; + return (char *)"credit";
Don't return a const string here. The result is suppoed to be allocated. You need to strdup it and don't forget the OOM check.
+} +
+ +/* +* xenapiNodeGetCellsFreeMemory +* +* +* Returns the number of entries filled in freeMems, or -1 in case of error. +*/ +static int +xenapiNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems ATTRIBUTE_UNUSED, + int startCell, int maxCells)
Remove ATTRIBUTE_UNUSED from freeMems.
+{ + if (maxCells >1 && startCell >0) { + xenapiSessionErrorHandler(conn, VIR_ERR_NO_SUPPORT, ""); + return -1; + } else { + freeMems[0] = xenapiNodeGetFreeMemory(conn); + return 1; + } +} +
+ +/* +* call_func +* sets curl options, used with xen_session_login_with_password +*/ +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func) +{ + (void)user_handle; + #ifdef PRINT_XML + + printf("\n\n---Data to server: -----------------------\n"); + printf("%s\n",((char*) data)); + fflush(stdout); + #endif + CURL *curl = curl_easy_init(); + if (!curl) { + return -1; + } + xen_comms comms = { + .func = result_func, + .handle = result_handle + }; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + #ifdef CURLOPT_MUTE + curl_easy_setopt(curl, CURLOPT_MUTE, 1); + #endif + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms); + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
You should set CURLOPT_SSL_VERIFYHOST to 2, with 1 the common name field is ignored. Or just don't change the SSL config. libcurl defaults to secure settings.
+ CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; +} +
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-02-26 15:15:55.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> + +#define PRINT_XML +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
+ +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf);
Use the virBuffer API instea of snprintf and strcat.
+ } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr);
Use virAsprintf instead of snprintf and strdup.
+ return ret; +} +
+ +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) + return -1; + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val);
OOM check missing.
+ return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} +
+ +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + *record = xen_vm_record_alloc(); + (*record)->name_label = strdup(def->name);
OOM check missing. As mentioned before, you're forgot to copy the UUID here.
+ if (STREQ(def->os.type,"hvm")) { + (*record)->hvm_boot_policy = strdup("BIOS order");
OOM check missing.
+ char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + (*record)->pv_bootloader = strdup("pygrub");
OOM check missing.
+ (*record)->pv_kernel = def->os.kernel; + (*record)->pv_ramdisk = def->os.initrd; + (*record)->pv_args = def->os.cmdline; + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + (*record)->pv_bootloader_args = def->os.bootloaderArgs; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<0)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<1)) + allocStringMap(&strings,(char *)"apci",(char *)"true"); + if (def->features & (1<<2)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + }
Use the virDomainFeature enum values here too.
+ if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + bridge = strdup(def->nets[i]->data.bridge.brname);
OOM check missing.
+ if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + mac = strdup(macStr);
OOM check missing.
+ } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + }
You need to free bridge here in the case mac is NULL but bridge is not.
+ } + } + return 0; +} +
Matthias

I've sent a patch containing most of the changes you'd suggested, except the Following ones. My comments inline.
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ +
+ +char *url=NULL;
You should move this into the xenapiPrivate struct, otherwise you'll have trouble using multiple XenAPI connections at the same time, because multiple calls to xenapiOpen will overwrite the pointer an leak the previous value.
url is passed to call_func() which is used by curl to talk to the server. Call_func() doesn't have access to 'conn', hence it can't be embedded there. I'll figure out a way to do this. The recent patch also has a SSL_verfiy flag which is global and used by call_func that should also be embedded similarly.
+* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) {
Is distro != windows a good indicator for paravirtualization mode? How do you detect the case when you have a non-windows system in HVM mode?
As of now, the hypervisor supports only windows in HVM.
diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
+ +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + char *ret=NULL; + int i, j; + mapstr[0] = 0; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf);
Use the virBuffer API instea of snprintf and strcat.
+ } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr);
Use virAsprintf instead of snprintf and strdup.
+ return ret; +} +
I couldn't find a way to match virBuffer APIs to do the exact operations as Above. Is there a strcat substitute in virBuffer APIs? Regards, Sharadha

2010/3/3 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
I've sent a patch containing most of the changes you'd suggested, except the Following ones. My comments inline.
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ +
+ +char *url=NULL;
You should move this into the xenapiPrivate struct, otherwise you'll have trouble using multiple XenAPI connections at the same time, because multiple calls to xenapiOpen will overwrite the pointer an leak the previous value.
url is passed to call_func() which is used by curl to talk to the server. Call_func() doesn't have access to 'conn', hence it can't be embedded there. I'll figure out a way to do this. The recent patch also has a SSL_verfiy flag which is global and used by call_func that should also be embedded similarly.
The second parameter for xen_session_login_with_password is a void pointer for user data. You can pass a pointer to the xenapiPrivate struct there. Then libxenserver will pass it to the call_func function as the user_handle parameter (I just verified this by looking at the libxenserver codebase). Regarding the no_verify query parameter: You should look at esxUtil_ParseQuery how the qparam_query_parse function is used there instead of parsing the URI yourself using strtok_r.
+* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) {
Is distro != windows a good indicator for paravirtualization mode? How do you detect the case when you have a non-windows system in HVM mode?
As of now, the hypervisor supports only windows in HVM.
I already installed Linux in Xen's HVM mode, that's why I asked. In that case your code would report paravirtualization mode, instead of HVM.
diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
+ +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
Okay, you could change it like this: - char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t len;
+ char *ret=NULL; + int i, j; + mapstr[0] = 0;
- mapstr[0] = 0;
+ for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf);
Use the virBuffer API instea of snprintf and strcat.
- snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); - strcat(mapstr, buf); + virBufferVSprintf(&buf, "%d,", (8 * i) + j); The buffer calls append new content and don't overwrite the existing buffer content.
+ } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr);
Use virAsprintf instead of snprintf and strdup.
- mapstr[strlen(mapstr) - 1] = 0; - snprintf(buf, sizeof(buf), "%d", vcpu); - ret = strdup(mapstr); + if (virBufferError(&buf)) { + virReportOOMError(); + virBufferFreeAndReset(&buf); + return NULL; + } Do error checking. + ret = virBufferContentAndReset(&buf); + len = strlen(ret); + if (len > 0 && ret[len - 1] == ',') + ret[len - 1] = 0; Strip a possibly trailing comma.
+ return ret; +} +
I couldn't find a way to match virBuffer APIs to do the exact operations as Above. Is there a strcat substitute in virBuffer APIs?
Regards, Sharadha
PS: Sorry, I missed your second patch for the configure script and stuff. I just looked at it and the logic for the libcurl check needs to be changed. I'll do a detailed review later. For the main patch, I think we should apply it after the 0.7.7 release, once the remaining major issues like the global variables are fixed, and fix remaining minor issues in additional patches. Matthias

I've updated the patch with the changes discussed in this mail. Patch just posted. Regards, Sharadha -----Original Message----- From: Matthias Bolte [mailto:matthias.bolte@googlemail.com] Sent: 03 March 2010 15:28 To: Sharadha Prabhakar (3P) Cc: libvir-list@redhat.com; Ewan Mellor Subject: Re: status on review comments 2010/3/3 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
I've sent a patch containing most of the changes you'd suggested, except the Following ones. My comments inline.
diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c --- ./libvirt_org/src/xenapi/xenapi_driver.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.c 2010-02-26 15:27:00.000000000 +0000 @@ -0,0 +1,1564 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ +
+ +char *url=NULL;
You should move this into the xenapiPrivate struct, otherwise you'll have trouble using multiple XenAPI connections at the same time, because multiple calls to xenapiOpen will overwrite the pointer an leak the previous value.
url is passed to call_func() which is used by curl to talk to the server. Call_func() doesn't have access to 'conn', hence it can't be embedded there. I'll figure out a way to do this. The recent patch also has a SSL_verfiy flag which is global and used by call_func that should also be embedded similarly.
The second parameter for xen_session_login_with_password is a void pointer for user data. You can pass a pointer to the xenapiPrivate struct there. Then libxenserver will pass it to the call_func function as the user_handle parameter (I just verified this by looking at the libxenserver codebase). Regarding the no_verify query parameter: You should look at esxUtil_ParseQuery how the qparam_query_parse function is used there instead of parsing the URI yourself using strtok_r.
+* +* Returns OS version on success or NULL in case of error +*/ +static char * +xenapiDomainGetOSType (virDomainPtr dom) +{ + /* vm.get_os-version */ + int i; + xen_vm vm; + char *os_version=NULL; + xen_vm_record *record; + xen_string_string_map *result; + char uuid[VIR_UUID_STRING_BUFLEN]; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; + virUUIDFormat(dom->uuid,uuid); + if (xen_vm_get_by_uuid(session, &vm, uuid)) { + xen_vm_get_record(session, &record, vm); + if (record) { + xen_vm_guest_metrics_get_os_version(session, &result, record->guest_metrics->u.handle); + if (result) { + for (i=0; i<(result->size); i++) { + if (STREQ(result->contents[i].key, "distro")) { + if (STREQ(result->contents[i].val, "windows")) {
Is distro != windows a good indicator for paravirtualization mode? How do you detect the case when you have a non-windows system in HVM mode?
As of now, the hypervisor supports only windows in HVM.
I already installed Linux in Xen's HVM mode, that's why I asked. In that case your code would report paravirtualization mode, instead of HVM.
diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-02-26 15:49:24.000000000 +0000 @@ -0,0 +1,433 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
+ +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned int vcpu, unsigned char *cpumap, int maplen) +{ + char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
Okay, you could change it like this: - char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64]; + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t len;
+ char *ret=NULL; + int i, j; + mapstr[0] = 0;
- mapstr[0] = 0;
+ for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); + strcat(mapstr, buf);
Use the virBuffer API instea of snprintf and strcat.
- snprintf(buf, sizeof(buf), "%d,", (8 * i) + j); - strcat(mapstr, buf); + virBufferVSprintf(&buf, "%d,", (8 * i) + j); The buffer calls append new content and don't overwrite the existing buffer content.
+ } + } + } + mapstr[strlen(mapstr) - 1] = 0; + snprintf(buf, sizeof(buf), "%d", vcpu); + ret = strdup(mapstr);
Use virAsprintf instead of snprintf and strdup.
- mapstr[strlen(mapstr) - 1] = 0; - snprintf(buf, sizeof(buf), "%d", vcpu); - ret = strdup(mapstr); + if (virBufferError(&buf)) { + virReportOOMError(); + virBufferFreeAndReset(&buf); + return NULL; + } Do error checking. + ret = virBufferContentAndReset(&buf); + len = strlen(ret); + if (len > 0 && ret[len - 1] == ',') + ret[len - 1] = 0; Strip a possibly trailing comma.
+ return ret; +} +
I couldn't find a way to match virBuffer APIs to do the exact operations as Above. Is there a strcat substitute in virBuffer APIs?
Regards, Sharadha
PS: Sorry, I missed your second patch for the configure script and stuff. I just looked at it and the logic for the libcurl check needs to be changed. I'll do a detailed review later. For the main patch, I think we should apply it after the 0.7.7 release, once the remaining major issues like the global variables are fixed, and fix remaining minor issues in additional patches. Matthias

This is the last patch in this series. It contains changes made to the following files. ~/libvirt/configure.ac ~/libvirt/src/Makefile.am ~/libvirt/src/util/virterror.c ~/libvirt/src/driver.h ~/libvirt/include/libvirt/virterror.h ~/libvirt/virterror.c --- ./libvirt_org/configure.ac 2010-02-17 17:39:21.000000000 +0000 +++ ./libvirt/configure.ac 2010-02-26 11:18:47.000000000 +0000 @@ -219,6 +219,8 @@ AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes]) AC_ARG_WITH([phyp], AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check]) +AC_ARG_WITH([xenapi], + AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=yes@:>@]),[],[with_xenapi=check]) AC_ARG_WITH([vbox], AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes]) AC_ARG_WITH([lxc], @@ -307,6 +309,7 @@ fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"]) + if test "$with_libvirtd" = "no" ; then with_qemu=no fi @@ -335,6 +338,49 @@ fi AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"]) + +old_LIBS="$LIBS" +old_CFLAGS="$CFLAGS" +LIBXENSERVER_LIBS="" +LIBXENSERVER_CFLAGS="" +LIBXENSERVER_LDFLAGS="" +dnl search for the XenServer library +if test "$with_xenapi" != "no" ; then + if test "$with_xenapi" != "yes" -a "$with_xenapi" != "check" ; then + LIBXENSERVER_CFLAGS="-I$with_xenapi/include" + LIBXENSERVER_LDFLAGS="$with_xenapi/libxenserver.so" + LIBXENSERVER_LIBS="-L$with_xenapi -lxenserver" + fi + fail=0 + CFLAGS="$CFLAGS $LIBXENSERVER_CFLAGS" + LIBS="$LIBS $LIBXENSERVER_LIBS" + AC_CHECK_LIB([xen_vm_start], [xs_read], [ + with_xenapi=yes + LIBXENSERVER_LIBS="$LIBXENSERVER_LIBS -lxenstore" + ],[ + if test "$with_xenapi" = "yes"; then + fail=1 + fi + with_xenapi=no + ]) +fi + +LIBS="$old_LIBS" +CFLAGS="$old_CFLAGS" + +if test $fail = 1; then + AC_MSG_ERROR([You must install the XenServer Library to compile XenAPI driver with -lxenserver]) +fi + +if test "$with_xenapi" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether Xen driver is enabled]) +fi + +AC_SUBST([LIBXENSERVER_CFLAGS]) +AC_SUBST([LIBXENSERVER_LIBS]) +AC_SUBST([LIBXENSERVER_LDFLAGS]) + + old_LIBS="$LIBS" old_CFLAGS="$CFLAGS" XEN_LIBS="" @@ -1447,23 +1493,31 @@ LIBCURL_LIBS="" LIBCURL_FOUND="no" -if test "$with_esx" = "yes" -o "$with_esx" = "check"; then +if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" = "yes" -o "$with_xenapi" = "check"; then PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [ LIBCURL_FOUND=yes with_esx="yes" + with_xenapi="yes" ], [ - if test "$with_esx" = "check"; then + if test "$with_esx" = "check" -o "$with_xenapi" = "check"; then with_esx=no - AC_MSG_NOTICE([libcurl is required for ESX driver, disabling it]) + with_xenapi=no + AC_MSG_NOTICE([libcurl is required for ESX/XENAPI driver, disabling it]) else - AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) + AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX/XENAPI driver]) fi ]) fi if test "$with_esx" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) fi + +if test "$with_xenapi" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi + AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) +AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) AC_SUBST([LIBCURL_CFLAGS]) AC_SUBST([LIBCURL_LIBS]) @@ -1894,6 +1948,7 @@ AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ PHYP: $with_phyp]) AC_MSG_NOTICE([ ONE: $with_one]) @@ -1992,6 +2047,12 @@ else AC_MSG_NOTICE([ xen: no]) fi +if test "$with_xenapi" = "yes" ; then +AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS $LIBXENSERVER_LDFLAGS]) +else +AC_MSG_NOTICE([ xen: no]) +fi if test "$with_hal" = "yes" ; then AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS]) else --- ./libvirt_org/src/Makefile.am 2010-02-17 17:38:13.000000000 +0000 +++ ./libvirt/src/Makefile.am 2010-02-26 13:13:59.000000000 +0000 @@ -205,6 +207,11 @@ qemu/qemu_security_dac.h \ qemu/qemu_security_dac.c +XENAPI_DRIVER_SOURCES = \ + xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ + xenapi_driver_private.h \ + xenapi/xenapi_utils.c xenapi/xenapi_utils.h + UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ uml/uml_driver.c uml/uml_driver.h @@ -466,6 +473,30 @@ libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES) endif +if WITH_XENAPI +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xenapi.la +else +noinst_LTLIBRARIES += libvirt_driver_xenapi.la + +libvirt_la_LIBADD += libvirt_driver_xenapi.la \ + $(LIBXENSERVER_LDFLAGS) +endif +#libvirt_driver_xenapi_la_LIBADD = $(LIBXENSERVER_LDFLAGS) +libvirt_driver_xenapi_la_CFLAGS = $(LIBXENSERVER_CFLAGS) \ + -I@top_srcdir@/src \ + -I@top_srcdir@/src/xenapi \ + -I@top_srcdir@/src/conf \ + $(LIBCURL_CFLAGS) +libvirt_driver_xenapi_la_LDFLAGS = $(LIBXENSERVER_LIBS) -g $(LIBXML_LIBS) \ + $(LIBCURL_LIBS) + +if WITH_DRIVER_MODULES +libvirt_driver_xenapi_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES) +endif + if WITH_QEMU if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_qemu.la @@ -722,6 +753,7 @@ $(OPENVZ_DRIVER_SOURCES) \ $(PHYP_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ + $(XENAPI_DRIVER_SOURCES) \ $(ESX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ --- ./libvirt_org/src/driver.h 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/driver.h 2010-02-18 10:45:54.000000000 +0000 @@ -27,6 +27,7 @@ VIR_DRV_ONE = 9, VIR_DRV_ESX = 10, VIR_DRV_PHYP = 11, + VIR_DRV_XENAPI = 12 } virDrvNo; --- ./libvirt_org/src/libvirt.c 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/libvirt.c 2010-02-18 12:21:43.000000000 +0000 @@ -64,6 +64,9 @@ #ifdef WITH_ESX #include "esx/esx_driver.h" #endif +#ifdef WITH_XENAPI +#include "xenapi/xenapi_driver.h" +#endif #endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -357,6 +360,7 @@ virDriverLoadModule("openvz"); virDriverLoadModule("vbox"); virDriverLoadModule("esx"); + virDriverLoadModule("xenapi"); virDriverLoadModule("remote"); #else #ifdef WITH_TEST @@ -377,6 +381,9 @@ #ifdef WITH_ESX if (esxRegister() == -1) return -1; #endif +#ifdef WITH_XENAPI + if (xenapiRegister () == -1) return -1; +#endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -1035,6 +1042,10 @@ if (STRCASEEQ(type, "Remote")) *typeVer = remoteVersion(); #endif +#if WITH_XENAPI + if (STRCASEEQ(type, "XenAPI")) + *typeVer = LIBVIR_VERSION_NUMBER; +#endif if (*typeVer == 0) { virLibConnError(NULL, VIR_ERR_NO_SUPPORT, type); goto error; --- ./libvirt_org/include/libvirt/virterror.h 2010-02-17 17:37:51.000000000 +0000 +++ ./libvirt/include/libvirt/virterror.h 2010-02-18 12:17:54.000000000 +0000 @@ -69,6 +69,7 @@ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ VIR_FROM_SECRET, /* Error from secret storage */ VIR_FROM_CPU, /* Error from CPU driver */ + VIR_FROM_XENAPI /* Error from XenAPI */ } virErrorDomain;
diff -ur ./libvirt_org/src/util/virterror.c ./libvirt/src/util/virterror.c --- ./libvirt_org/src/util/virterror.c 2010-02-17 17:38:14.000000000 +0000 +++ ./libvirt/src/util/virterror.c 2010-02-18 12:13:08.000000000 +0000 @@ -85,6 +85,9 @@ case VIR_FROM_XEN: dom = "Xen "; break; + case VIR_FROM_XENAPI: + dom = "XenAPI "; + break; case VIR_FROM_XML: dom = "XML "; break;

2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
This is the last patch in this series. It contains changes made to the following files. ~/libvirt/configure.ac ~/libvirt/src/Makefile.am ~/libvirt/src/util/virterror.c ~/libvirt/src/driver.h ~/libvirt/include/libvirt/virterror.h ~/libvirt/virterror.c
--- ./libvirt_org/configure.ac 2010-02-17 17:39:21.000000000 +0000 +++ ./libvirt/configure.ac 2010-02-26 11:18:47.000000000 +0000 @@ -219,6 +219,8 @@ AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes]) AC_ARG_WITH([phyp], AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check]) +AC_ARG_WITH([xenapi], + AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=yes@:>@]),[],[with_xenapi=check])
The actual default and the printed one mismatch. change default=yes to default=check
AC_ARG_WITH([vbox], AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes]) AC_ARG_WITH([lxc], @@ -307,6 +309,7 @@ fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"])
+ if test "$with_libvirtd" = "no" ; then with_qemu=no fi @@ -335,6 +338,49 @@ fi AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"])
+ +old_LIBS="$LIBS" +old_CFLAGS="$CFLAGS" +LIBXENSERVER_LIBS="" +LIBXENSERVER_CFLAGS="" +LIBXENSERVER_LDFLAGS="" +dnl search for the XenServer library +if test "$with_xenapi" != "no" ; then + if test "$with_xenapi" != "yes" -a "$with_xenapi" != "check" ; then + LIBXENSERVER_CFLAGS="-I$with_xenapi/include" + LIBXENSERVER_LDFLAGS="$with_xenapi/libxenserver.so"
Why do you add the path to an .so file to the LDFLAGS?
+ LIBXENSERVER_LIBS="-L$with_xenapi -lxenserver" + fi + fail=0 + CFLAGS="$CFLAGS $LIBXENSERVER_CFLAGS" + LIBS="$LIBS $LIBXENSERVER_LIBS" + AC_CHECK_LIB([xen_vm_start], [xs_read], [
I'm not sure that I understand what you're doing here. You're checking for a xs_read function in a xen_vm_start library.
+ with_xenapi=yes + LIBXENSERVER_LIBS="$LIBXENSERVER_LIBS -lxenstore"
Do you really need xenstore?
+ ],[ + if test "$with_xenapi" = "yes"; then + fail=1 + fi + with_xenapi=no + ]) +fi + +LIBS="$old_LIBS" +CFLAGS="$old_CFLAGS" + +if test $fail = 1; then + AC_MSG_ERROR([You must install the XenServer Library to compile XenAPI driver with -lxenserver]) +fi + +if test "$with_xenapi" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether Xen driver is enabled])
'XenAPI driver' instead of 'Xen driver'
+fi + +AC_SUBST([LIBXENSERVER_CFLAGS]) +AC_SUBST([LIBXENSERVER_LIBS]) +AC_SUBST([LIBXENSERVER_LDFLAGS]) + +
old_LIBS="$LIBS" old_CFLAGS="$CFLAGS" XEN_LIBS="" @@ -1447,23 +1493,31 @@ LIBCURL_LIBS="" LIBCURL_FOUND="no"
-if test "$with_esx" = "yes" -o "$with_esx" = "check"; then +if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" = "yes" -o "$with_xenapi" = "check"; then PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [ LIBCURL_FOUND=yes with_esx="yes" + with_xenapi="yes"
This part should be split into an ESX and XenAPI part. Otherwise you may change with_esx="no" to with_esx="yes" just because libcurl was found.
], [ - if test "$with_esx" = "check"; then + if test "$with_esx" = "check" -o "$with_xenapi" = "check"; then with_esx=no - AC_MSG_NOTICE([libcurl is required for ESX driver, disabling it]) + with_xenapi=no + AC_MSG_NOTICE([libcurl is required for ESX/XENAPI driver, disabling it]) else - AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) + AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX/XENAPI driver]) fi
Also this part should be split into an ESX and XenAPI part.
]) fi if test "$with_esx" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) fi + +if test "$with_xenapi" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi + AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) +AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) AC_SUBST([LIBCURL_CFLAGS]) AC_SUBST([LIBCURL_LIBS])
I suggest to restructure this tests like this: dnl dnl check for libcurl (ESX/XenAPI) dnl LIBCURL_CFLAGS="" LIBCURL_LIBS="" if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" = "yes" -o "$with_xenapi" = "check"; then PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [ if test "$with_esx" = "check"; then with_esx=yes fi if test "$with_xenapi" = "check"; then with_xenapi=yes fi ], [ if test "$with_esx" = "check"; then with_esx=no AC_MSG_NOTICE([libcurl is required for the ESX driver, disabling it]) elif test "$with_esx" = "yes"; then AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) fi if test "$with_xenapi" = "check"; then with_xenapi=no AC_MSG_NOTICE([libcurl is required for the XenAPI driver, disabling it]) elif test "$with_xenapi" = "yes"; then AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the XenAPI driver]) fi ]) fi if test "$with_esx" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) fi AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) if test "$with_xenapi" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) fi AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) AC_SUBST([LIBCURL_CFLAGS]) AC_SUBST([LIBCURL_LIBS])
@@ -1894,6 +1948,7 @@ AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ PHYP: $with_phyp]) AC_MSG_NOTICE([ ONE: $with_one]) @@ -1992,6 +2047,12 @@ else AC_MSG_NOTICE([ xen: no]) fi +if test "$with_xenapi" = "yes" ; then +AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS $LIBXENSERVER_LDFLAGS]) +else +AC_MSG_NOTICE([ xen: no])
'xenapi: no' instead of 'xen: no'.
+fi if test "$with_hal" = "yes" ; then AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS]) else --- ./libvirt_org/src/Makefile.am 2010-02-17 17:38:13.000000000 +0000 +++ ./libvirt/src/Makefile.am 2010-02-26 13:13:59.000000000 +0000 @@ -205,6 +207,11 @@ qemu/qemu_security_dac.h \ qemu/qemu_security_dac.c
+XENAPI_DRIVER_SOURCES = \ + xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ + xenapi_driver_private.h \ + xenapi/xenapi_utils.c xenapi/xenapi_utils.h + UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ uml/uml_driver.c uml/uml_driver.h @@ -466,6 +473,30 @@ libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES) endif
+if WITH_XENAPI +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xenapi.la +else +noinst_LTLIBRARIES += libvirt_driver_xenapi.la + +libvirt_la_LIBADD += libvirt_driver_xenapi.la \ + $(LIBXENSERVER_LDFLAGS)
LIBXENSERVER_LDFLAGS is not necessary here. Adding LIBXENSERVER_LIBS to libvirt_driver_xenapi_la_LDFLAGS some lines below should be enough. Matthias

Please see my comments inline. The diff content of PATCH 2/2 with the changes is submitted at the end of this mail. @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes])
AC_ARG_WITH([phyp], AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check]) +AC_ARG_WITH([xenapi], + AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=yes@:>@]),[],[with_xenapi=check])
The actual default and the printed one mismatch. change default=yes to default=check
This has been changed.
AC_ARG_WITH([vbox], AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes]) AC_ARG_WITH([lxc], @@ -307,6 +309,7 @@ fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"])
+ if test "$with_libvirtd" = "no" ; then with_qemu=no fi @@ -335,6 +338,49 @@ fi AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"])
+ +old_LIBS="$LIBS" +old_CFLAGS="$CFLAGS" +LIBXENSERVER_LIBS="" +LIBXENSERVER_CFLAGS="" +LIBXENSERVER_LDFLAGS="" +dnl search for the XenServer library +if test "$with_xenapi" != "no" ; then + if test "$with_xenapi" != "yes" -a "$with_xenapi" != "check" ; then + LIBXENSERVER_CFLAGS="-I$with_xenapi/include" + LIBXENSERVER_LDFLAGS="$with_xenapi/libxenserver.so"
Why do you add the path to an .so file to the LDFLAGS? I wasn't sure that adding LIBXENSERVER_LIBS to xenapi_ldflags would Suffice. LIBXENSERVER_LDFLAGS has been removed now.
+ LIBXENSERVER_LIBS="-L$with_xenapi -lxenserver" + fi + fail=0 + CFLAGS="$CFLAGS $LIBXENSERVER_CFLAGS" + LIBS="$LIBS $LIBXENSERVER_LIBS" + AC_CHECK_LIB([xen_vm_start], [xs_read], [
I'm not sure that I understand what you're doing here. You're checking for a xs_read function in a xen_vm_start library.
This has been changed to check for the function xen_vm_start in libxenserver.
+ with_xenapi=yes + LIBXENSERVER_LIBS="$LIBXENSERVER_LIBS -lxenstore"
Do you really need xenstore? No. It has been changed to -lxenserver
+ ],[ + if test "$with_xenapi" = "yes"; then + fail=1 + fi + with_xenapi=no + ]) +fi + +LIBS="$old_LIBS" +CFLAGS="$old_CFLAGS" + +if test $fail = 1; then + AC_MSG_ERROR([You must install the XenServer Library to compile XenAPI driver with -lxenserver]) +fi + +if test "$with_xenapi" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether Xen driver is enabled])
'XenAPI driver' instead of 'Xen driver' Done
+fi + +AC_SUBST([LIBXENSERVER_CFLAGS]) +AC_SUBST([LIBXENSERVER_LIBS]) +AC_SUBST([LIBXENSERVER_LDFLAGS]) + +
old_LIBS="$LIBS" old_CFLAGS="$CFLAGS" XEN_LIBS="" @@ -1447,23 +1493,31 @@ LIBCURL_LIBS="" LIBCURL_FOUND="no"
-if test "$with_esx" = "yes" -o "$with_esx" = "check"; then +if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" = "yes" -o "$with_xenapi" = "check"; >then PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [ LIBCURL_FOUND=yes with_esx="yes" + with_xenapi="yes"
This part should be split into an ESX and XenAPI part. Otherwise you may change with_esx="no" to with_esx="yes" just because libcurl was found.
], [ - if test "$with_esx" = "check"; then + if test "$with_esx" = "check" -o "$with_xenapi" = "check"; then with_esx=no - AC_MSG_NOTICE([libcurl is required for ESX driver, disabling it]) + with_xenapi=no + AC_MSG_NOTICE([libcurl is required for ESX/XENAPI driver, disabling it]) else - AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) + AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX/XENAPI driver]) fi
Also this part should be split into an ESX and XenAPI part.
]) fi if test "$with_esx" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) fi + +if test "$with_xenapi" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi + AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) +AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) AC_SUBST([LIBCURL_CFLAGS]) AC_SUBST([LIBCURL_LIBS])
I suggest to restructure this tests like this:
dnl dnl check for libcurl (ESX/XenAPI) dnl LIBCURL_CFLAGS="" LIBCURL_LIBS="" if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" = "yes" -o "$with_xenapi" = "check"; then PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [ if test "$with_esx" = "check"; then with_esx=yes fi if test "$with_xenapi" = "check"; then with_xenapi=yes fi ], [ if test "$with_esx" = "check"; then with_esx=no AC_MSG_NOTICE([libcurl is required for the ESX driver, disabling it]) elif test "$with_esx" = "yes"; then AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) fi if test "$with_xenapi" = "check"; then with_xenapi=no AC_MSG_NOTICE([libcurl is required for the XenAPI driver, disabling it]) elif test "$with_xenapi" = "yes"; then AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the XenAPI driver]) fi ]) fi if test "$with_esx" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) fi AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) if test "$with_xenapi" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) fi AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) AC_SUBST([LIBCURL_CFLAGS]) AC_SUBST([LIBCURL_LIBS]) --this bit has been added and the previous code removed
@@ -1894,6 +1948,7 @@ AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ PHYP: $with_phyp]) AC_MSG_NOTICE([ ONE: $with_one]) @@ -1992,6 +2047,12 @@ else AC_MSG_NOTICE([ xen: no]) fi +if test "$with_xenapi" = "yes" ; then +AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS $LIBXENSERVER_LDFLAGS]) +else +AC_MSG_NOTICE([ xen: no])
'xenapi: no' instead of 'xen: no'. Done
+fi if test "$with_hal" = "yes" ; then AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS]) else --- ./libvirt_org/src/Makefile.am 2010-02-17 17:38:13.000000000 +0000 +++ ./libvirt/src/Makefile.am 2010-02-26 13:13:59.000000000 +0000 @@ -205,6 +207,11 @@ qemu/qemu_security_dac.h \ qemu/qemu_security_dac.c
+XENAPI_DRIVER_SOURCES = \ + xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ + xenapi_driver_private.h \ + xenapi/xenapi_utils.c xenapi/xenapi_utils.h + UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ uml/uml_driver.c uml/uml_driver.h @@ -466,6 +473,30 @@ libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES) endif
+if WITH_XENAPI +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xenapi.la +else +noinst_LTLIBRARIES += libvirt_driver_xenapi.la + +libvirt_la_LIBADD += libvirt_driver_xenapi.la \ + $(LIBXENSERVER_LDFLAGS)
LIBXENSERVER_LDFLAGS is not necessary here. Adding LIBXENSERVER_LIBS to libvirt_driver_xenapi_la_LDFLAGS some lines below should be enough.
LIBXENSERVER_LDFLAGS has been removed from here and the configure script too. --------------------------PATCH 2/2 BELOW------------------------------------ --- ./libvirt_org/configure.ac 2010-02-17 17:39:21.000000000 +0000 +++ ./libvirt/configure.ac 2010-03-05 13:26:45.000000000 +0000 @@ -219,6 +219,8 @@ AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes]) AC_ARG_WITH([phyp], AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check]) +AC_ARG_WITH([xenapi], + AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=check@:>@]),[],[with_xenapi=check]) AC_ARG_WITH([vbox], AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes]) AC_ARG_WITH([lxc], @@ -307,6 +309,7 @@ fi AM_CONDITIONAL([WITH_VBOX], [test "$with_vbox" = "yes"]) + if test "$with_libvirtd" = "no" ; then with_qemu=no fi @@ -335,6 +338,46 @@ fi AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"]) + +old_LIBS="$LIBS" +old_CFLAGS="$CFLAGS" +LIBXENSERVER_LIBS="" +LIBXENSERVER_CFLAGS="" +dnl search for the XenServer library +if test "$with_xenapi" != "no" ; then + if test "$with_xenapi" != "yes" -a "$with_xenapi" != "check" ; then + LIBXENSERVER_CFLAGS="-I$with_xenapi/include" + LIBXENSERVER_LIBS="-L$with_xenapi" + fi + fail=0 + CFLAGS="$CFLAGS $LIBXENSERVER_CFLAGS" + LIBS="$LIBS $LIBXENSERVER_LIBS" + AC_CHECK_LIB([xenserver], [xen_vm_start], [ + with_xenapi=yes + LIBXENSERVER_LIBS="$LIBXENSERVER_LIBS -lxenserver" + ],[ + if test "$with_xenapi" = "yes"; then + fail=1 + fi + with_xenapi=no + ]) +fi + +LIBS="$old_LIBS" +CFLAGS="$old_CFLAGS" + +if test $fail = 1; then + AC_MSG_ERROR([You must install the XenServer Library to compile XenAPI driver with -lxenserver]) +fi + +if test "$with_xenapi" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi + +AC_SUBST([LIBXENSERVER_CFLAGS]) +AC_SUBST([LIBXENSERVER_LIBS]) + + old_LIBS="$LIBS" old_CFLAGS="$CFLAGS" XEN_LIBS="" @@ -1440,31 +1483,51 @@ AC_SUBST([LIBPARTED_LIBS]) dnl -dnl check for libcurl (ESX) +dnl check for libcurl (ESX/XenAPI) dnl LIBCURL_CFLAGS="" LIBCURL_LIBS="" -LIBCURL_FOUND="no" -if test "$with_esx" = "yes" -o "$with_esx" = "check"; then +if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" += "yes" -o "$with_xenapi" = "check"; then PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [ - LIBCURL_FOUND=yes - with_esx="yes" + if test "$with_esx" = "check"; then + with_esx=yes + fi + + if test "$with_xenapi" = "check"; then + with_xenapi=yes + fi ], [ if test "$with_esx" = "check"; then with_esx=no - AC_MSG_NOTICE([libcurl is required for ESX driver, disabling it]) - else + AC_MSG_NOTICE([libcurl is required for the ESX driver, disabling it]) + elif test "$with_esx" = "yes"; then AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver]) fi + + if test "$with_xenapi" = "check"; then + with_xenapi=no + AC_MSG_NOTICE([libcurl is required for the XenAPI driver, disabling it]) + elif test "$with_xenapi" = "yes"; then + AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the XenAPI driver]) + fi ]) fi + + if test "$with_esx" = "yes" ; then - AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) -fi + AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled]) +fi AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"]) +if test "$with_xenapi" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled]) +fi +AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"]) + + AC_SUBST([LIBCURL_CFLAGS]) AC_SUBST([LIBCURL_LIBS]) @@ -1894,6 +1957,7 @@ AC_MSG_NOTICE([ UML: $with_uml]) AC_MSG_NOTICE([ OpenVZ: $with_openvz]) AC_MSG_NOTICE([ VBox: $with_vbox]) +AC_MSG_NOTICE([ XenAPI: $with_xenapi]) AC_MSG_NOTICE([ LXC: $with_lxc]) AC_MSG_NOTICE([ PHYP: $with_phyp]) AC_MSG_NOTICE([ ONE: $with_one]) @@ -1992,6 +2056,11 @@ else AC_MSG_NOTICE([ xen: no]) fi +if test "$with_xenapi" = "yes" ; then +AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS ]) +else +AC_MSG_NOTICE([ xenapi: no]) +fi if test "$with_hal" = "yes" ; then AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS]) else --- ./libvirt_org/src/Makefile.am 2010-02-17 17:38:13.000000000 +0000 +++ ./libvirt/src/Makefile.am 2010-03-05 11:49:58.000000000 +0000 @@ -3,6 +3,8 @@ # No libraries with the exception of LIBXML should be listed # here. List them against the individual XXX_la_CFLAGS targets # that actually use them + + INCLUDES = \ -I$(top_srcdir)/gnulib/lib \ -I../gnulib/lib \ @@ -205,6 +207,11 @@ qemu/qemu_security_dac.h \ qemu/qemu_security_dac.c +XENAPI_DRIVER_SOURCES = \ + xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ + xenapi_driver_private.h \ + xenapi/xenapi_utils.c xenapi/xenapi_utils.h + UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ uml/uml_driver.c uml/uml_driver.h @@ -466,6 +473,28 @@ libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES) endif +if WITH_XENAPI +if WITH_DRIVER_MODULES +mod_LTLIBRARIES += libvirt_driver_xenapi.la +else +noinst_LTLIBRARIES += libvirt_driver_xenapi.la + +libvirt_la_LIBADD += libvirt_driver_xenapi.la +endif +libvirt_driver_xenapi_la_CFLAGS = $(LIBXENSERVER_CFLAGS) \ + -I@top_srcdir@/src \ + -I@top_srcdir@/src/xenapi \ + -I@top_srcdir@/src/conf \ + $(LIBCURL_CFLAGS) +libvirt_driver_xenapi_la_LDFLAGS = $(LIBXENSERVER_LIBS) -g $(LIBXML_LIBS) \ + $(LIBCURL_LIBS) + +if WITH_DRIVER_MODULES +libvirt_driver_xenapi_la_LDFLAGS += -module -avoid-version +endif +libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES) +endif + if WITH_QEMU if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_qemu.la @@ -722,6 +751,7 @@ $(OPENVZ_DRIVER_SOURCES) \ $(PHYP_DRIVER_SOURCES) \ $(VBOX_DRIVER_SOURCES) \ + $(XENAPI_DRIVER_SOURCES) \ $(ESX_DRIVER_SOURCES) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ --- ./libvirt_org/src/driver.h 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/driver.h 2010-02-18 10:45:54.000000000 +0000 @@ -27,6 +27,7 @@ VIR_DRV_ONE = 9, VIR_DRV_ESX = 10, VIR_DRV_PHYP = 11, + VIR_DRV_XENAPI = 12 } virDrvNo; --- ./libvirt_org/src/libvirt.c 2010-02-17 17:38:08.000000000 +0000 +++ ./libvirt/src/libvirt.c 2010-02-18 12:21:43.000000000 +0000 @@ -64,6 +64,9 @@ #ifdef WITH_ESX #include "esx/esx_driver.h" #endif +#ifdef WITH_XENAPI +#include "xenapi/xenapi_driver.h" +#endif #endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -357,6 +360,7 @@ virDriverLoadModule("openvz"); virDriverLoadModule("vbox"); virDriverLoadModule("esx"); + virDriverLoadModule("xenapi"); virDriverLoadModule("remote"); #else #ifdef WITH_TEST @@ -377,6 +381,9 @@ #ifdef WITH_ESX if (esxRegister() == -1) return -1; #endif +#ifdef WITH_XENAPI + if (xenapiRegister () == -1) return -1; #endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif @@ -1035,6 +1042,10 @@ if (STRCASEEQ(type, "Remote")) *typeVer = remoteVersion(); #endif +#if WITH_XENAPI + if (STRCASEEQ(type, "XenAPI")) + *typeVer = LIBVIR_VERSION_NUMBER; #endif if (*typeVer == 0) { virLibConnError(NULL, VIR_ERR_NO_SUPPORT, type); goto error; diff--- ./libvirt_org/include/libvirt/virterror.h 2010-02-17 17:37:51.000000000 +0000 diff+++ ./libvirt/include/libvirt/virterror.h 2010-02-18 12:17:54.000000000 +0000 @@ -69,6 +69,7 @@ VIR_FROM_PHYP, /* Error from IBM power hypervisor */ VIR_FROM_SECRET, /* Error from secret storage */ VIR_FROM_CPU, /* Error from CPU driver */ + VIR_FROM_XENAPI /* Error from XenAPI */ } virErrorDomain;
diff -ur ./libvirt_org/src/util/virterror.c ./libvirt/src/util/virterror.c --- ./libvirt_org/src/util/virterror.c 2010-02-17 17:38:14.000000000 +0000 +++ ./libvirt/src/util/virterror.c 2010-02-18 12:13:08.000000000 +0000 @@ -85,6 +85,9 @@ case VIR_FROM_XEN: dom = "Xen "; break; + case VIR_FROM_XENAPI: + dom = "XenAPI "; + break; case VIR_FROM_XML: dom = "XML "; break;

2010/3/5 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Please see my comments inline. The diff content of PATCH 2/2 with the changes is submitted at the end of this mail.
Okay, this patch looks good now. I tried to apply it but the patch seems mangled. It seems that you copy and pasted the content of the patch into the mail body and your mail program mangled it. Please resend this patch, but attach the patch as file to the mail, so your mail program does not mangle it. Matthias

On 03/05/2010 02:42 PM, Matthias Bolte wrote:
2010/3/5 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Please see my comments inline. The diff content of PATCH 2/2 with the changes is submitted at the end of this mail.
Okay, this patch looks good now. I tried to apply it but the patch seems mangled. It seems that you copy and pasted the content of the patch into the mail body and your mail program mangled it.
Please resend this patch, but attach the patch as file to the mail, so your mail program does not mangle it.
Or consider using 'git send-email', which can be configured to automatically send mail without even having to go through your mailer. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

Resending patch 2 as attachment. Sharadha -----Original Message----- From: Matthias Bolte [mailto:matthias.bolte@googlemail.com] Sent: 05 March 2010 21:42 To: Sharadha Prabhakar (3P) Cc: libvir-list@redhat.com; Ewan Mellor Subject: Re: [libvirt] [PATCH 2/2] Addition of XenAPI support to libvirt 2010/3/5 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Please see my comments inline. The diff content of PATCH 2/2 with the changes is submitted at the end of this mail.
Okay, this patch looks good now. I tried to apply it but the patch seems mangled. It seems that you copy and pasted the content of the patch into the mail body and your mail program mangled it. Please resend this patch, but attach the patch as file to the mail, so your mail program does not mangle it. Matthias
participants (5)
-
Daniel P. Berrange
-
Eric Blake
-
Jiri Denemark
-
Matthias Bolte
-
Sharadha Prabhakar (3P)