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@xxxxxxxxxx> +*/ + +#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@xxxxxxxxxx> +*/ + +#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@xxxxxxxxxx> +*/ + +#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@xxxxxxxxxx> + */ + + +#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@xxxxxxxxxx> + */ + + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx 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@xxxxxxxxxx> +*/ + +#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@xxxxxxxxxx> +*/ + +#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@xxxxxxxxxx> +*/ + +#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@xxxxxxxxxx> + */ + + +#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@xxxxxxxxxx> + */ + + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxxxxxx] Sent: 26 February 2010 20:00 To: Sharadha Prabhakar (3P) Cc: libvir-list@xxxxxxxxxx; Ewan Mellor Subject: Re: [libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt 2010/2/26 Sharadha Prabhakar (3P) <sharadha.prabhakar@xxxxxxxxxx>: > 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@xxxxxxxxxx> > +*/ > + > + > +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@xxxxxxxxxx> > + */ > + > + > +#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@xxxxxxxxxx> > + */ > + > + > +/* 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list