Re: [libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt

Patch includes 1) Modification of xenapiDomainGetOSType 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-04 16:59:01.000000000 +0000 @@ -0,0 +1,1738 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/ + +#include <config.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "domain_conf.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" + + +/* +*getCapsObject +* +*Build the capabilities of the hypervisor +*Return virCapsPtr on success or NULL on failure +*/ +static virCapsPtr +getCapsObject (void) +{ + virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0); + if (!caps) { + virReportOOMError(); + return NULL; + } + virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0, "", "", 0, NULL); + if (!guest1) + goto error_cleanup; + virCapsGuestDomainPtr domain1 = virCapabilitiesAddGuestDomain(guest1, "xen", "", "", 0, NULL); + if (!domain1) + goto error_cleanup; + virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0, "", "", 0, NULL); + if (!guest2) + goto error_cleanup; + virCapsGuestDomainPtr domain2 = virCapabilitiesAddGuestDomain(guest2, "xen", "", "", 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; + } + if (!(xen_host_get_hostname(session, &result, host))) + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL); + 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); + 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) +{ + xen_vm vm=NULL; + xen_vm_set *vms; + char *ostype = NULL; + char *boot_policy=NULL; + 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 NULL; + } + if (vms->size!=1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique"); + xen_vm_set_free(vms); + return NULL; + } + vm = vms->contents[0]; + if(!xen_vm_get_hvm_boot_policy(session, &boot_policy, vm)) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL); + goto cleanup; + } + if (!(ostype=(STREQ(boot_policy,"BIOS order")?strdup("hvm"):strdup("xen")))) + virReportOOMError(); + VIR_FREE(boot_policy); + cleanup: + xen_vm_set_free(vms); + return ostype; +} +/* +* 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.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-26 13:21:50.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_PRIV_H__ +#define __VIR_XENAPI_PRIV_H__ + + +extern int xenapiRegister (void); + + +#endif /* __VIR_XENAPI_PRIV_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-03-03 16:09:47.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + + +#ifndef __VIR_XENAPI_H__ +#define __VIR_XENAPI_H__ + +#include <xen/api/xen_common.h> +#include <libxml/tree.h> +#include "virterror_internal.h" + +//#define PRINT_XML +#define VIR_FROM_THIS VIR_FROM_XENAPI +#define LIBVIRT_MODELNAME_LEN (32) +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \ + buf,__FILE__,__FUNCTION__,__LINE__) + +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno); + +typedef struct +{ + xen_result_func func; + void *handle; +} xen_comms; + + +int +call_func(const void *data, size_t len, void *user_handle, + void *result_handle, xen_result_func result_func); +size_t +write_func(void *ptr, size_t size, size_t nmemb, void *comms); + +/* xenAPI driver's private data structure */ +struct _xenapiPrivate { + xen_session *session; + void *handle; + char *uname; + char *pwd; + char *url; + int SSLflag; + virCapsPtr caps; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-03-03 18:01:06.000000000 +0000 @@ -0,0 +1,578 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "domain_conf.h" +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" +#include "xenapi_utils.h" +#include "util/logging.h" +#include "qparams.h" + + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname) +{ + unsigned int ncred; + virConnectCredential cred; + char *prompt; + + memset(&cred, 0, sizeof(virConnectCredential)); + + if (virAsprintf(&prompt, "Enter %s password for %s", username, + hostname) < 0) { + return NULL; + } + + for (ncred = 0; ncred < auth->ncredtype; ncred++) { + if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE && + auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) { + continue; + } + + cred.type = auth->credtype[ncred]; + cred.prompt = prompt; + cred.challenge = hostname; + cred.defresult = NULL; + cred.result = NULL; + cred.resultlen = 0; + + if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) { + VIR_FREE(cred.result); + } + + break; + } + + VIR_FREE(prompt); + + return cred.result; +} + +int +xenapiUtil_ParseQuery(virConnectPtr conn, xmlURIPtr uri, int *noVerify) +{ + int result = 0; + int i; + struct qparam_set *queryParamSet = NULL; + struct qparam *queryParam = NULL; + +#ifdef HAVE_XMLURI_QUERY_RAW + queryParamSet = qparam_query_parse(uri->query_raw); +#else + queryParamSet = qparam_query_parse(uri->query); +#endif + + if (queryParamSet == NULL) { + goto failure; + } + + for (i = 0; i < queryParamSet->n; i++) { + queryParam = &queryParamSet->p[i]; + if (STRCASEEQ(queryParam->name, "no_verify")) { + if (noVerify == NULL) { + continue; + } + if (virStrToLong_i(queryParam->value, NULL, 10, noVerify) < 0 || + (*noVerify != 0 && *noVerify != 1)) { + xenapiSessionErrorHandler(conn, VIR_ERR_INVALID_ARG, + "Query parameter 'no_verify' has unexpected value (should be 0 or 1)"); + goto failure; + } + } + } + + cleanup: + if (queryParamSet != NULL) { + free_qparam_set(queryParamSet); + } + + return result; + + failure: + result = -1; + + goto cleanup; +} + + + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_normal_exit num = XEN_ON_NORMAL_EXIT_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_NORMAL_EXIT_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_NORMAL_EXIT_RESTART; + return num; +} + + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action) +{ + enum xen_on_crash_behaviour num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + if (action == VIR_DOMAIN_LIFECYCLE_DESTROY) + num = XEN_ON_CRASH_BEHAVIOUR_DESTROY; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART) + num = XEN_ON_CRASH_BEHAVIOUR_RESTART; + else if (action == VIR_DOMAIN_LIFECYCLE_PRESERVE) + num = XEN_ON_CRASH_BEHAVIOUR_PRESERVE; + else if (action == VIR_DOMAIN_LIFECYCLE_RESTART_RENAME) + num = XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART; + return num; +} + +/* generate XenAPI boot order format from libvirt format */ +char * +createXenAPIBootOrderString(int nboot, int *bootDevs) +{ + virBuffer ret = VIR_BUFFER_INITIALIZER; + char *val = NULL; + int i; + for (i=0;i<nboot;i++) { + if (bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) + val = (char *)"a"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_DISK) + val = (char *)"c"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) + val = (char *)"d"; + else if (bootDevs[i] == VIR_DOMAIN_BOOT_NET) + val = (char *)"n"; + if (val) + virBufferEscapeString(&ret,"%s",val); + } + return virBufferContentAndReset(&ret); +} + +/* convert boot order string to libvirt boot order enum */ +enum virDomainBootOrder +map2LibvirtBootOrder(char c) { + switch(c) { + case 'a': + return VIR_DOMAIN_BOOT_FLOPPY; + case 'c': + return VIR_DOMAIN_BOOT_DISK; + case 'd': + return VIR_DOMAIN_BOOT_CDROM; + case 'n': + return VIR_DOMAIN_BOOT_NET; + default: + return -1; + } +} + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_NORMAL_EXIT_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_NORMAL_EXIT_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + return num; +} + + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action) +{ + enum virDomainLifecycleAction num = VIR_DOMAIN_LIFECYCLE_RESTART; + if (action == XEN_ON_CRASH_BEHAVIOUR_DESTROY) + num = VIR_DOMAIN_LIFECYCLE_DESTROY; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART; + else if (action == XEN_ON_CRASH_BEHAVIOUR_PRESERVE) + num = VIR_DOMAIN_LIFECYCLE_PRESERVE; + else if (action == XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART) + num = VIR_DOMAIN_LIFECYCLE_RESTART_RENAME; + return num; +} + + + +/* returns 'file' or 'block' for the storage type */ +int +getStorageVolumeType(char *type) +{ + if((STREQ(type,"lvmoiscsi")) || + (STREQ(type,"lvmohba")) || + (STREQ(type,"lvm")) || + (STREQ(type,"file")) || + (STREQ(type,"iso")) || + (STREQ(type,"ext")) || + (STREQ(type,"nfs"))) + return (int)VIR_STORAGE_VOL_FILE; + else if((STREQ(type,"iscsi")) || + (STREQ(type,"equal")) || + (STREQ(type,"hba")) || + (STREQ(type,"cslg")) || + (STREQ(type,"udev")) || + (STREQ(type,"netapp"))) + return (int)VIR_STORAGE_VOL_BLOCK; + return -1; +} + +/* returns error description if any received from the server */ +char * +returnErrorFromSession(xen_session *session) +{ + int i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + for (i=0; i<session->error_description_count-1; i++) { + if (!i) + virBufferEscapeString(&buf,"%s",session->error_description[i]); + else + virBufferEscapeString(&buf," : %s",session->error_description[i]); + } + return virBufferContentAndReset(&buf); +} + +/* converts bitmap to string of the form '1,2...' */ +char * +mapDomainPinVcpu(unsigned char *cpumap, int maplen) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t len; + char *ret=NULL; + int i, j; + for (i = 0; i < maplen; i++) { + for (j = 0; j < 8; j++) { + if (cpumap[i] & (1 << j)) { + virBufferVSprintf(&buf,"%d,", (8*i)+j); + } + } + } + if (virBufferError(&buf)) { + virReportOOMError(); + virBufferFreeAndReset(&buf); + return NULL; + } + ret = virBufferContentAndReset(&buf); + len = strlen(ret); + if (len > 0 && ret[len - 1] == ',') + ret[len - 1] = 0; + return ret; +} + +/* obtains the CPU bitmap from the string passed */ +void +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen) +{ + int pos; + int max_bits = maplen * 8; + char *num = NULL,*bp=NULL; + bzero(cpumap, maplen); + num = strtok_r (mask, ",", &bp); + while (num != NULL) { + if (sscanf (num, "%d", &pos)!=1) + virReportOOMError(); + if (pos<0 || pos>max_bits-1) + VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits); + else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok_r (NULL, ",", &bp); + } +} + + +/* mapping XenServer power state to Libvirt power state */ +virDomainState +mapPowerState(enum xen_vm_power_state state) +{ + virDomainState virState; + switch (state) { + case (XEN_VM_POWER_STATE_HALTED): + case (XEN_VM_POWER_STATE_SUSPENDED): + virState = VIR_DOMAIN_SHUTOFF; + break; + case (XEN_VM_POWER_STATE_PAUSED): + virState = VIR_DOMAIN_PAUSED; + break; + case (XEN_VM_POWER_STATE_RUNNING): + virState = VIR_DOMAIN_RUNNING; + break; + case (XEN_VM_POWER_STATE_UNKNOWN): + case (XEN_VM_POWER_STATE_UNDEFINED): + virState = VIR_DOMAIN_NOSTATE; + break; + default: + virState = VIR_DOMAIN_NOSTATE; + break; + } + return virState; +} + +/* allocate a flexible array and fill values(key,val) */ +int +allocStringMap (xen_string_string_map **strings, char *key, char *val) +{ + int sz = ((*strings) == NULL)?0:(*strings)->size; + sz++; + if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+ + sizeof(xen_string_string_map_contents)*sz)<0) { + virReportOOMError(); + return -1; + } + (*strings)->size = sz; + (*strings)->contents[sz-1].key = strdup(key); + (*strings)->contents[sz-1].val = strdup(val); + return 0; +} + +/* Error handling function returns error messages from the server if any */ +void +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum, + const char *buf, const char *filename, const char *func, size_t lineno) +{ + if (buf==NULL) { + char *ret=NULL; + ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session); + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret); + xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session); + VIR_FREE(ret); + } else { + virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf); + } +} + +/* creates network intereface for VM */ +int +createVifNetwork (virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac) +{ + xen_vm xvm = NULL; + char *uuid = NULL; + xen_vm_get_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, &uuid, vm); + if (uuid) { + if(!xen_vm_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &xvm, uuid)) + return -1; + VIR_FREE(uuid); + } + xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc(); + vm_opt->is_record = 0; + vm_opt->u.handle = xvm; + xen_network_set *net_set = NULL; + xen_network_record *net_rec = NULL; + int cnt=0; + if (xen_network_get_all(((struct _xenapiPrivate *)(conn->privateData))->session, &net_set)) { + for(cnt=0;cnt<(net_set->size);cnt++) { + if (xen_network_get_record(((struct _xenapiPrivate *)(conn->privateData))->session, + &net_rec, net_set->contents[cnt])) { + if (STREQ(net_rec->bridge,bridge)) { + break; + } else { + xen_network_record_free(net_rec); + } + } + } + } + if ( (cnt<net_set->size) && net_rec) { + xen_network network = NULL; + xen_network_get_by_uuid(((struct _xenapiPrivate *)(conn->privateData))->session, + &network, net_rec->uuid); + xen_network_record_opt *network_opt = xen_network_record_opt_alloc(); + network_opt->is_record = 0; + network_opt->u.handle = network; + xen_vif_record *vif_record = xen_vif_record_alloc(); + vif_record->mac = mac; + vif_record->vm = vm_opt; + vif_record->network = network_opt; + xen_vif vif=NULL; + + vif_record->other_config = xen_string_string_map_alloc(0); + vif_record->runtime_properties = xen_string_string_map_alloc(0); + vif_record->qos_algorithm_params = xen_string_string_map_alloc(0); + vif_record->device = strdup(device); + xen_vif_create(((struct _xenapiPrivate *)(conn->privateData))->session, + &vif, vif_record); + if (!vif) { + xen_vif_free(vif); + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + xen_network_set_free(net_set); + return 0; + } + xen_vif_record_free(vif_record); + xen_network_record_free(net_rec); + } + if (net_set!=NULL) xen_network_set_free(net_set); + return -1; +} + +/* Create a VM record from the XML description */ +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + xen_vm_record **record, xen_vm *vm) +{ + char uuidStr[VIR_UUID_STRING_BUFLEN]; + *record = xen_vm_record_alloc(); + if (!((*record)->name_label = strdup(def->name))) + goto error_cleanup; + if (def->uuid) { + virUUIDFormat(def->uuid,uuidStr); + if (!((*record)->uuid = strdup(uuidStr))) + goto error_cleanup; + } + if (STREQ(def->os.type,"hvm")) { + if(!((*record)->hvm_boot_policy = strdup("BIOS order"))) + goto error_cleanup; + char *boot_order = NULL; + if (def->os.nBootDevs!=0) + boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]); + if (boot_order!=NULL) { + xen_string_string_map *hvm_boot_params=NULL; + allocStringMap(&hvm_boot_params, (char *)"order",boot_order); + (*record)->hvm_boot_params = hvm_boot_params; + VIR_FREE(boot_order); + } + } else if (STREQ(def->os.type,"xen")) { + if (!((*record)->pv_bootloader = strdup("pygrub"))) + goto error_cleanup; + if (def->os.kernel){ + if (!((*record)->pv_kernel = strdup(def->os.kernel))) + goto error_cleanup; + } + if (def->os.initrd) { + if (!((*record)->pv_ramdisk = strdup(def->os.initrd))) + goto error_cleanup; + } + if(def->os.cmdline) { + if (!((*record)->pv_args = strdup(def->os.cmdline))) + goto error_cleanup; + } + (*record)->hvm_boot_params = xen_string_string_map_alloc(0); + } + if (def->os.bootloaderArgs) + if(!((*record)->pv_bootloader_args = strdup(def->os.bootloaderArgs))) + goto error_cleanup; + + if (def->memory) + (*record)->memory_static_max = (int64_t) (def->memory * 1024); + if (def->maxmem) + (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024); + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + + if (def->vcpus) { + (*record)->vcpus_max = (int64_t) def->vcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) + (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff); + if (def->onReboot) + (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot); + if (def->onCrash) + (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash); + + xen_string_string_map *strings=NULL; + if (def->features) { + if (def->features & (1<<VIR_DOMAIN_FEATURE_ACPI)) + allocStringMap(&strings,(char *)"acpi",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_APIC)) + allocStringMap(&strings,(char *)"apic",(char *)"true"); + if (def->features & (1<<VIR_DOMAIN_FEATURE_PAE)) + allocStringMap(&strings,(char *)"pae",(char *)"true"); + } + if (strings!=NULL) + (*record)->platform = strings; + + (*record)->vcpus_params = xen_string_string_map_alloc(0); + (*record)->other_config = xen_string_string_map_alloc(0); + (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0); + (*record)->xenstore_data = xen_string_string_map_alloc(0); + (*record)->hvm_shadow_multiplier = 1.000; + if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session, + vm, *record)) { + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + + int device_number=0; + char *bridge=NULL,*mac=NULL; + int i; + for (i=0;i<def->nnets;i++) { + if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + if (def->nets[i]->data.bridge.brname) + if(!(bridge = strdup(def->nets[i]->data.bridge.brname))) + goto error_cleanup; + if (def->nets[i]->mac) { + char macStr[VIR_MAC_STRING_BUFLEN]; + virFormatMacAddr(def->nets[i]->mac, macStr); + if(!(mac = strdup(macStr))) { + if (bridge) VIR_FREE(bridge); + goto error_cleanup; + } + } + if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + } + if (bridge) VIR_FREE(bridge); + /*if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + if (createVifNetwork(conn, *vm, device, bridge, mac)<0) { + VIR_FREE(mac); + VIR_FREE(bridge); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + VIR_FREE(bridge); + device_number++; + } else { + if (bridge) + VIR_FREE(bridge); + if (mac) + VIR_FREE(mac); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + }*/ + } + } + return 0; + + error_cleanup: + virReportOOMError(); + xen_vm_record_free(*record); + return -1; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-03-03 18:01:19.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ + +#ifndef _VIR_XENAPI_UTILS_ +#define _VIR_XENAPI_UTILS_ + +#include <stdio.h> +#include <string.h> +#include <config.h> + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <libxml/uri.h> +#include <xen_internal.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include <xen/api/xen_common.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_vm.h> +#include <xen/api/xen_all.h> +#include <xen/api/xen_vm_metrics.h> + +#include "libvirt_internal.h" +#include "libvirt/libvirt.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "conf/domain_conf.h" +#include "xenapi_driver_private.h" +#include "util.h" +#include "uuid.h" +#include "memory.h" +#include "driver.h" +#include "buf.h" + +#define NETWORK_DEVID_SIZE (10) + +typedef uint64_t cpumap_t; + +char * +xenapiUtil_RequestPassword(virConnectAuthPtr auth, const char *username, + const char *hostname); + +int +xenapiUtil_ParseQuery(virConnectPtr conn, xmlURIPtr uri, int *noVerify); + +enum xen_on_normal_exit +actionShutdownLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +enum xen_on_crash_behaviour +actionCrashLibvirt2XenapiEnum(enum virDomainLifecycleAction action); + +char * +createXenAPIBootOrderString(int nboot, int *bootDevs); + +enum virDomainBootOrder map2LibvirtBootOrder(char c); + +enum virDomainLifecycleAction +xenapiNormalExitEnum2virDomainLifecycle(enum xen_on_normal_exit action); + +enum virDomainLifecycleAction +xenapiCrashExitEnum2virDomainLifecycle(enum xen_on_crash_behaviour action); + +void getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen); + +int getStorageVolumeType(char *type); + +char *returnErrorFromSession(xen_session *session); + +virDomainState +mapPowerState(enum xen_vm_power_state state); + +char * +mapDomainPinVcpu(unsigned char *cpumap, int maplen); + +int +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr defPtr, + xen_vm_record **record, xen_vm *vm); + +int +allocStringMap (xen_string_string_map **strings, char *key, char *val); + +int +createVifNetwork(virConnectPtr conn, xen_vm vm, char *device, + char *bridge, char *mac); + +#endif //_VIR_XENAPI_UTILS_

2010/3/5 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Patch includes 1) Modification of xenapiDomainGetOSType 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-04 16:59:01.000000000 +0000 @@ -0,0 +1,1738 @@ + +/* + * xenapi_driver.c: Xen API driver. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> +*/
A license statement is missing. Using LGPL like the rest of libvirt would be a good choice.
+ +/* +*getCapsObject +* +*Build the capabilities of the hypervisor +*Return virCapsPtr on success or NULL on failure +*/ +static virCapsPtr +getCapsObject (void) +{ + virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0);
You're ignoring the actual host architecture here and assume x86_64 even if the host is just x86.
+ if (!caps) { + virReportOOMError(); + return NULL; + } + virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0, "", "", 0, NULL); + if (!guest1) + goto error_cleanup; + virCapsGuestDomainPtr domain1 = virCapabilitiesAddGuestDomain(guest1, "xen", "", "", 0, NULL); + if (!domain1) + goto error_cleanup; + virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0, "", "", 0, NULL); + if (!guest2) + goto error_cleanup; + virCapsGuestDomainPtr domain2 = virCapabilitiesAddGuestDomain(guest2, "xen", "", "", 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;
Initialize passwd to NULL.
+ 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'");
The given URI is not for you, this is no error, so don't report an error, just return VIR_DRV_OPEN_DECLINED.
+ 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) {
You should use || instead of &&, otherwise you won't catch cases where passwd is NULL but conn->uri->user isn't and via versa.
+ xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid");
You may leak passwd here. Free is using VIR_FREE(passwd).
+ return VIR_DRV_OPEN_ERROR; + } + if (VIR_ALLOC(privP) < 0) { + virReportOOMError();
You leak passwd here too.
+ return VIR_DRV_OPEN_ERROR; + } + if (virAsprintf(&(privP->url),"https://%s",conn->uri->server) < 0) { + virReportOOMError();
You may leak passwd here too.
+ 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);
No need to cast privP to void *. Shouldn't the parameter after the username be passwd instead of hardcoding "xenroot"?
+ + if ( session && session->ok ) { + privP->session = session; + virCapsPtr caps = getCapsObject(); + if (caps) + privP->caps = caps;
Why not directly assign caps: privP->caps = getCapsObject(); getCapsObject() may fail you need to check the return value for NULL, and report an error.
+ conn->privateData = privP;
You leak passwd here too.
+ return VIR_DRV_OPEN_SUCCESS; + } else { + xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,""); + VIR_FREE(privP);
You may also get here if session is not NULL but session->ok is false. I assume session is allocated, so you need to free it here by some free function, maybe xen_session_logout does this. You leak passwd here too.
+ return VIR_DRV_OPEN_ERROR; + } +} +
+ + +/* +* 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();
If sscanf fails to parse 3 items, then this is no OOM error.
+ 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; +} + +
+ +/* +* 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;
You need to report an OOM error if virCapabilitiesFormatXML returns NULL.
+ } + 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]);
Maybe you should check if the ID doesn't fit into an int and report an error in that case, instead of just masking out the upper 32bit.
+ ids[i] = (int)(t0 & 0xffffffff); + } + xen_vm_set_free(result); + return i; + } + return -1; +} +
+ +/* +* xenapiDomainCreateXML +* +* Launches a new domain based on the XML description +* Returns the domain pointer or NULL in case of error +*/ +static virDomainPtr +xenapiDomainCreateXML (virConnectPtr conn, + const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags)
Normally ATTRIBUTE_UNUSED is placed behind the parameter, not in front of it.
+{ + 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; +} +
+ +/* +* 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");
You should distinguish between vms->size < 1 and vms->size > 1. If there is no domain with a given name you'll report an error that says that the domain name is not unique. Or is vms->size >= 1 guaranteed if xen_vm_get_by_name_label succeeds? If not then this applies to all other fucntions too, where you check vms->size != 1.
+ 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; + } + }
You're leaking vms here.
+ } + xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL); + return NULL; +} +
+/* +* 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);
Is mem_static_max a value in byte? libvirt expects this value in kilobyte.
+ } 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 mem_static_max is in byte then you need to multiply memory by 1024, because memory is in kilobyte.
+ 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; +} +
+ +/* +* 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) {
Don't allocate domInfo here, just use a virDomainInfo directly on the stack, like you do it with virNodeInfo.
+ virReportOOMError(); + return -1; + } + if (virDomainGetInfo(dom,domInfo)==0) {
You should not call libvirt public API functions from here. You can call xenapiDomainGetInfo directly.
+ nvcpus = domInfo->nrVirtCpu; + VIR_FREE(domInfo);
If you put domInfo on the stack, remove this free call.
+ } else { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information"); + return -1; + } + if ( virNodeGetInfo(dom->conn,&nodeInfo)==0)
Just call xenapiNodeGetInfo directly here.
+ 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; +} +
+ +/* +* 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)
Put ATTRIBUTE_UNUSED behind the parameter.
+{ + 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;
I think you can break the for loop here.
+ } + } + 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);
If you've already srtdup'ed some names when an error occurs, then you're leaking this already strdup'ed names here.
+ 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);
And here you may leak already strdup'ed names too. you need to free them in bot cases.
+ return -1; + } + } + doms=j; + xen_vm_set_free(result); + return doms; + } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); + 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; + 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);
You set SSLflag to 0 or 2 depending on the no_verify query parameter in xenapiOpen. For CURLOPT_SSL_VERIFYHOST 2 is the correct value, but CURLOPT_SSL_VERIFYPEER expects 0 or 1. Instead of having the SSLflag in the xenapiPrivate struct you could have the noVerify value there and then decide here to what values this maps. For example curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, priv->noVerify ? 0 : 1); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, priv->noVerify ? 0 : 2);
+ CURLcode result = curl_easy_perform(curl); + curl_easy_cleanup(curl); + return result; + +} + + + diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h --- ./libvirt_org/src/xenapi/xenapi_driver.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver.h 2010-02-26 13:21:50.000000000 +0000 @@ -0,0 +1,15 @@ +/* + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */
As in xenapi_driver.c, a license statement is missing here.
+ +#ifndef __VIR_XENAPI_PRIV_H__ +#define __VIR_XENAPI_PRIV_H__ + + +extern int xenapiRegister (void); + + +#endif /* __VIR_XENAPI_PRIV_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h --- ./libvirt_org/src/xenapi/xenapi_driver_private.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_driver_private.h 2010-03-03 16:09:47.000000000 +0000 @@ -0,0 +1,49 @@ +/* + * xenapi_driver_private.h: Xen API driver's private header file. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */
A license statement is missing here too.
+ +#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;
I think handle, uname, and pwd are actually unused. If that's true you could remove them from the struct.
+ char *url; + int SSLflag; + virCapsPtr caps; +}; + +#endif /* __VIR_XENAPI_H__ */ diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c --- ./libvirt_org/src/xenapi/xenapi_utils.c 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-03-03 18:01:06.000000000 +0000 @@ -0,0 +1,578 @@ +/* + * xenapi_utils.c: Xen API driver -- utils parts. + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */
A license statement is missing here too.
+ +/* 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();
It isn't an OOM error if sscanf fails.
+ if (pos<0 || pos>max_bits-1) + VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits);
Do not append \n, that'll be done automatically.
+ else + (cpumap)[pos/8] |= (1<<(pos%8)); + num = strtok_r (NULL, ",", &bp); + } +} + +
+ +/* 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);
You should check if strdup returned NULL.
+ 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); + }
No need to append \n here too.
+} +
+ +/* 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";
You defined NETWORK_DEVID_SIZE to be 10, but 10 is to small for an int value. You need at least two more chars, one for a possible minus sign and one for the null terminator.
+ sprintf(device,"%d",device_number); + createVifNetwork(conn, *vm, device, bridge, mac); + VIR_FREE(bridge); + device_number++; + } + if (bridge) VIR_FREE(bridge); + /*if (mac!=NULL && bridge!=NULL) { + char device[NETWORK_DEVID_SIZE]="\0"; + sprintf(device,"%d",device_number); + if (createVifNetwork(conn, *vm, device, bridge, mac)<0) { + VIR_FREE(mac); + VIR_FREE(bridge); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + } + VIR_FREE(bridge); + device_number++; + } else { + if (bridge) + VIR_FREE(bridge); + if (mac) + VIR_FREE(mac); + xen_vm_record_free(*record); + xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL); + return -1; + }*/ + } + } + return 0; + + error_cleanup: + virReportOOMError(); + xen_vm_record_free(*record); + return -1; +} + diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h --- ./libvirt_org/src/xenapi/xenapi_utils.h 1970-01-01 01:00:00.000000000 +0100 +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-03-03 18:01:19.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * xenapi_utils.h: Xen API driver -- utils header + * Copyright (C) 2009 Citrix Ltd. + * Sharadha Prabhakar <sharadha.prabhakar@citrix.com> + */ +
A license statement is missing here too.
+ +#define NETWORK_DEVID_SIZE (10) +
Should be at least 12. Another thing you probably should fix is the definition of varaibles in the middle of blocks. Variables should be defined at the beginning of a block. Okay, mostly minor issues. I think the next version of this patch can be applied and remaining issues can be fixed by additional patches. Matthias

Patch 1 is sent as attachment. It contains changes suggested in this mail. Some comments inline. Sharadha -----Original Message----- From: Matthias Bolte [mailto:matthias.bolte@googlemail.com] Sent: 05 March 2010 23:32 To: Sharadha Prabhakar (3P) Cc: libvir-list@redhat.com; Ewan Mellor Subject: Re: [libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt 2010/3/5 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Patch includes 1) Modification of xenapiDomainGetOSType 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
+ +/* +*getCapsObject +* +*Build the capabilities of the hypervisor +*Return virCapsPtr on success or NULL on failure +*/ +static virCapsPtr +getCapsObject (void) +{ + virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0);
You're ignoring the actual host architecture here and assume x86_64 even if the host is just x86.
X86_64 is the only architecture supported as of now.
+/* +* 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");
You should distinguish between vms->size < 1 and vms->size > 1. If there is no domain with a given name you'll report an error that says that the domain name is not unique.
Or is vms->size >= 1 guaranteed if xen_vm_get_by_name_label succeeds? If not then this applies to all other fucntions too, where you check vms->size != 1.
Yes. If vms->size<=0 then no domain error is returned and if vms->size!=1 Domain name is not unique error is returned.
+/* +* 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);
Is mem_static_max a value in byte? libvirt expects this value in kilobyte.
Yes
+ } 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 mem_static_max is in byte then you need to multiply memory by 1024, because memory is in kilobyte.
This has been changed to return kilobyte
Okay, mostly minor issues. I think the next version of this patch can be applied and remaining issues can be fixed by additional patches.
Matthias

2010/3/9 Sharadha Prabhakar (3P) <sharadha.prabhakar@citrix.com>:
Patch 1 is sent as attachment. It contains changes suggested in this mail. Some comments inline. Sharadha
Okay, I applied and pushed the patches. Thanks! I tried to setup a Citric XenServer in order to test the driver, but I failed. XenServer supports x86_64 only and I have currently no x86_64 server to spare for this, so I tried installing it as ESX guest, but failed. The installer complains about a non-x86_64 system. At that point I gave up testing for now. The code as is looks good now. There are some minor issues left, like variable declarations in the middle of a block. The last major issue the username handling. If no username is passed in the URI, you're using NULL. Matthias
participants (2)
-
Matthias Bolte
-
Sharadha Prabhakar (3P)