提交 eb9945d9 编写于 作者: S Sharadha Prabhakar 提交者: Matthias Bolte

xenapi: Initial commit of the new driver

上级 102d25a8
......@@ -219,6 +219,8 @@ AC_ARG_WITH([libssh2],
AC_HELP_STRING([--with-libssh2=@<:@PFX@:>@], [libssh2 location @<:@default=/usr/local/lib@:>@]),[],[with_libssh2=yes])
AC_ARG_WITH([phyp],
AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check])
AC_ARG_WITH([xenapi],
AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=check@:>@]),[],[with_xenapi=check])
AC_ARG_WITH([vbox],
AC_HELP_STRING([--with-vbox], [add VirtualBox support @<:@default=yes@:>@]),[],[with_vbox=yes])
AC_ARG_WITH([lxc],
......@@ -341,6 +343,46 @@ if test "$with_libvirtd" = "yes" ; then
fi
AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"])
old_LIBS="$LIBS"
old_CFLAGS="$CFLAGS"
LIBXENSERVER_LIBS=""
LIBXENSERVER_CFLAGS=""
dnl search for the XenServer library
if test "$with_xenapi" != "no" ; then
if test "$with_xenapi" != "yes" -a "$with_xenapi" != "check" ; then
LIBXENSERVER_CFLAGS="-I$with_xenapi/include"
LIBXENSERVER_LIBS="-L$with_xenapi"
fi
fail=0
CFLAGS="$CFLAGS $LIBXENSERVER_CFLAGS"
LIBS="$LIBS $LIBXENSERVER_LIBS"
AC_CHECK_LIB([xenserver], [xen_vm_start], [
with_xenapi=yes
LIBXENSERVER_LIBS="$LIBXENSERVER_LIBS -lxenserver"
],[
if test "$with_xenapi" = "yes"; then
fail=1
fi
with_xenapi=no
])
fi
LIBS="$old_LIBS"
CFLAGS="$old_CFLAGS"
if test $fail = 1; then
AC_MSG_ERROR([You must install the XenServer Library to compile XenAPI driver with -lxenserver])
fi
if test "$with_xenapi" = "yes"; then
AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled])
fi
AC_SUBST([LIBXENSERVER_CFLAGS])
AC_SUBST([LIBXENSERVER_LIBS])
old_LIBS="$LIBS"
old_CFLAGS="$CFLAGS"
XEN_LIBS=""
......@@ -1446,31 +1488,50 @@ AC_SUBST([LIBPARTED_CFLAGS])
AC_SUBST([LIBPARTED_LIBS])
dnl
dnl check for libcurl (ESX)
dnl check for libcurl (ESX/XenAPI)
dnl
LIBCURL_CFLAGS=""
LIBCURL_LIBS=""
LIBCURL_FOUND="no"
if test "$with_esx" = "yes" -o "$with_esx" = "check"; then
if test "$with_esx" = "yes" -o "$with_esx" = "check" -o "$with_xenapi" = "yes" -o "$with_xenapi" = "check"; then
PKG_CHECK_MODULES(LIBCURL, libcurl >= $LIBCURL_REQUIRED, [
LIBCURL_FOUND=yes
with_esx="yes"
if test "$with_esx" = "check"; then
with_esx=yes
fi
if test "$with_xenapi" = "check"; then
with_xenapi=yes
fi
], [
if test "$with_esx" = "check"; then
with_esx=no
AC_MSG_NOTICE([libcurl is required for ESX driver, disabling it])
else
AC_MSG_NOTICE([libcurl is required for the ESX driver, disabling it])
elif test "$with_esx" = "yes"; then
AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the ESX driver])
fi
if test "$with_xenapi" = "check"; then
with_xenapi=no
AC_MSG_NOTICE([libcurl is required for the XenAPI driver, disabling it])
elif test "$with_xenapi" = "yes"; then
AC_MSG_ERROR([libcurl >= $LIBCURL_REQUIRED is required for the XenAPI driver])
fi
])
fi
if test "$with_esx" = "yes" ; then
AC_DEFINE_UNQUOTED([WITH_ESX], 1, [whether ESX driver is enabled])
fi
AM_CONDITIONAL([WITH_ESX], [test "$with_esx" = "yes"])
if test "$with_xenapi" = "yes" ; then
AC_DEFINE_UNQUOTED([WITH_XENAPI], 1, [whether XenAPI driver is enabled])
fi
AM_CONDITIONAL([WITH_XENAPI], [test "$with_xenapi" = "yes"])
AC_SUBST([LIBCURL_CFLAGS])
AC_SUBST([LIBCURL_LIBS])
......@@ -1909,6 +1970,7 @@ AC_MSG_NOTICE([ QEMU: $with_qemu])
AC_MSG_NOTICE([ UML: $with_uml])
AC_MSG_NOTICE([ OpenVZ: $with_openvz])
AC_MSG_NOTICE([ VBox: $with_vbox])
AC_MSG_NOTICE([ XenAPI: $with_xenapi])
AC_MSG_NOTICE([ LXC: $with_lxc])
AC_MSG_NOTICE([ PHYP: $with_phyp])
AC_MSG_NOTICE([ ONE: $with_one])
......@@ -2007,6 +2069,11 @@ AC_MSG_NOTICE([ xen: $XEN_CFLAGS $XEN_LIBS])
else
AC_MSG_NOTICE([ xen: no])
fi
if test "$with_xenapi" = "yes" ; then
AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS])
else
AC_MSG_NOTICE([ xenapi: no])
fi
if test "$with_hal" = "yes" ; then
AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS])
else
......
......@@ -69,6 +69,7 @@ typedef enum {
VIR_FROM_PHYP, /* Error from IBM power hypervisor */
VIR_FROM_SECRET, /* Error from secret storage */
VIR_FROM_CPU, /* Error from CPU driver */
VIR_FROM_XENAPI /* Error from XenAPI */
} virErrorDomain;
......
......@@ -205,6 +205,11 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_security_dac.h \
qemu/qemu_security_dac.c
XENAPI_DRIVER_SOURCES = \
xenapi/xenapi_driver.c xenapi/xenapi_driver.h \
xenapi_driver_private.h \
xenapi/xenapi_utils.c xenapi/xenapi_utils.h
UML_DRIVER_SOURCES = \
uml/uml_conf.c uml/uml_conf.h \
uml/uml_driver.c uml/uml_driver.h
......@@ -467,6 +472,22 @@ libvirt_driver_vbox_la_LIBADD = $(DLOPEN_LIBS)
libvirt_driver_vbox_la_SOURCES = $(VBOX_DRIVER_SOURCES)
endif
if WITH_XENAPI
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_xenapi.la
else
noinst_LTLIBRARIES += libvirt_driver_xenapi.la
libvirt_la_LIBADD += libvirt_driver_xenapi.la
endif
libvirt_driver_xenapi_la_CFLAGS = $(LIBXENSERVER_CFLAGS) $(LIBCURL_CFLAGS) \
-I@top_srcdir@/src/conf
libvirt_driver_xenapi_la_LDFLAGS = $(LIBXENSERVER_LIBS) $(LIBCURL_LIBS)
if WITH_DRIVER_MODULES
libvirt_driver_xenapi_la_LDFLAGS += -module -avoid-version
endif
libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES)
endif
if WITH_QEMU
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_qemu.la
......@@ -723,6 +744,7 @@ EXTRA_DIST += \
$(OPENVZ_DRIVER_SOURCES) \
$(PHYP_DRIVER_SOURCES) \
$(VBOX_DRIVER_SOURCES) \
$(XENAPI_DRIVER_SOURCES) \
$(ESX_DRIVER_SOURCES) \
$(NETWORK_DRIVER_SOURCES) \
$(INTERFACE_DRIVER_SOURCES) \
......
......@@ -27,6 +27,7 @@ typedef enum {
VIR_DRV_ONE = 9,
VIR_DRV_ESX = 10,
VIR_DRV_PHYP = 11,
VIR_DRV_XENAPI = 12
} virDrvNo;
......
......@@ -64,6 +64,9 @@
# ifdef WITH_ESX
# include "esx/esx_driver.h"
# endif
# ifdef WITH_XENAPI
# include "xenapi/xenapi_driver.h"
# endif
#endif
#define VIR_FROM_THIS VIR_FROM_NONE
......@@ -357,6 +360,7 @@ virInitialize(void)
virDriverLoadModule("openvz");
virDriverLoadModule("vbox");
virDriverLoadModule("esx");
virDriverLoadModule("xenapi");
virDriverLoadModule("remote");
#else
# ifdef WITH_TEST
......@@ -377,6 +381,9 @@ virInitialize(void)
# ifdef WITH_ESX
if (esxRegister() == -1) return -1;
# endif
# ifdef WITH_XENAPI
if (xenapiRegister() == -1) return -1;
# endif
# ifdef WITH_REMOTE
if (remoteRegister () == -1) return -1;
# endif
......@@ -1031,6 +1038,10 @@ virGetVersion(unsigned long *libVer, const char *type,
if (STRCASEEQ(type, "ESX"))
*typeVer = LIBVIR_VERSION_NUMBER;
# endif
# if WITH_XENAPI
if (STRCASEEQ(type, "XenAPI"))
*typeVer = LIBVIR_VERSION_NUMBER;
# endif
# if WITH_REMOTE
if (STRCASEEQ(type, "Remote"))
*typeVer = remoteVersion();
......
......@@ -85,6 +85,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
case VIR_FROM_XEN:
dom = "Xen ";
break;
case VIR_FROM_XENAPI:
dom = "XenAPI ";
break;
case VIR_FROM_XML:
dom = "XML ";
break;
......
/*
* xenapi_driver.c: Xen API driver.
* Copyright (C) 2009, 2010 Citrix Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Sharadha Prabhakar <sharadha.prabhakar@citrix.com>
*/
#include <config.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <libxml/uri.h>
#include <curl/curl.h>
#include <xen/api/xen_all.h>
#include "internal.h"
#include "domain_conf.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "util.h"
#include "uuid.h"
#include "memory.h"
#include "buf.h"
#include "xenapi_driver.h"
#include "xenapi_driver_private.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 = NULL;
xen_session *session;
struct _xenapiPrivate *privP;
if (STRCASENEQ(conn->uri->scheme, "XenAPI")) {
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");
if (passwd) VIR_FREE(passwd);
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();
VIR_FREE(passwd);
return VIR_DRV_OPEN_ERROR;
}
xenapiUtil_ParseQuery(conn, conn->uri, &privP->noVerify);
xmlInitParser();
xmlKeepBlanksDefault(0);
xen_init();
curl_global_init(CURL_GLOBAL_ALL);
session = xen_session_login_with_password(call_func, privP, conn->uri->user, passwd, xen_api_latest_version);
if (session && session->ok) {
privP->session = session;
if (!(privP->caps = getCapsObject())) {
xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Capabilities not found");
VIR_FREE(passwd);
return VIR_DRV_OPEN_ERROR;
}
conn->privateData = privP;
VIR_FREE(passwd);
return VIR_DRV_OPEN_SUCCESS;
} else {
xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED, "");
if (session) xenSessionFree(session);
VIR_FREE(privP);
VIR_FREE(passwd);
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;
int i;
char *version = NULL;
unsigned long major = 0, minor = 0, release = 0;
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) {
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) {
if (sscanf(version, "%ld.%ld.%ld", &major, &minor, &release) != 3) {
xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get version info");
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);
if (!xml) goto cleanup;
return xml;
}
cleanup:
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;
int64_t t0;
int i;
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) {
for (i = 0; (i < (result->size)) && (i < maxids); i++) {
xen_vm_get_domid(session, &t0, result->contents[i]);
if (t0 > (int64_t)INT_MAX || t0 < (int64_t)INT_MIN) {
xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "DomainID can't fit in 32 bits");
xen_vm_set_free(result);
return -1;
}
ids[i] = (int)t0;
}
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,
unsigned int flags ATTRIBUTE_UNUSED)
{
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) && vms->size > 0) {
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_INTERNAL_ERROR, "Couldn't get the Domain Pointer");
return NULL;
}
}
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, "");
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=NULL;
xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
if (xen_vm_get_by_name_label(session, &vms, dom->name) && vms->size > 0) {
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;
}
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* 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) && vms->size > 0) {
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;
}
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* 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) && vms->size > 0) {
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;
}
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* 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) && vms->size > 0) {
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;
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* 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) && vms->size > 0) {
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;
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* 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) && vms->size > 0) {
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);
} else
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
cleanup:
if (vms) 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) && vms->size > 0) {
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 {
if (vms) xen_vm_set_free(vms);
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) && vms->size > 0) {
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 * 1024))) {
xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL);
xen_vm_set_free(vms);
return -1;
}
xen_vm_set_free(vms);
} else {
if (vms) xen_vm_set_free(vms);
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) && vms->size > 0) {
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;
}
if (vms) xen_vm_set_free(vms);
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) && vms->size > 0) {
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;
}
}
if (vms) xen_vm_set_free(vms);
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) && vms->size > 0) {
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;
}
}
if (vms) xen_vm_set_free(vms);
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;
virDomainInfo 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 (xenapiDomainGetInfo(dom, &domInfo) == 0) {
nvcpus = domInfo.nrVirtCpu;
} else {
xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information");
return -1;
}
if (xenapiNodeGetInfo(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) && vms->size > 0) {
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;
}
if (vms) xen_vm_set_free(vms);
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, int flags ATTRIBUTE_UNUSED)
{
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(defPtr->uuid, 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;
break;
}
}
xen_string_string_map_free(result);
}
VIR_FREE(boot_policy);
} else {
char *value = NULL;
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;
}
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 = NULL;
if (!(usenames = strdup(record->name_label))) {
virReportOOMError();
xen_vm_record_free(record);
xen_vm_set_free(result);
while (--j >= 0) VIR_FREE(names[j]);
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);
while (--j >= 0) VIR_FREE(names[j]);
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) && vms->size > 0) {
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 {
if (vms) xen_vm_set_free(vms);
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) && vms->size > 0) {
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;
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* xenapiDomainGetAutostart
*
* Provides a boolean value indicating whether the domain configured
* to be automatically started when the host machine boots
* Return 0 on success or -1 in case of error
*/
static int
xenapiDomainGetAutostart (virDomainPtr dom, int *autostart)
{
int i,flag=0;
xen_vm_set *vms;
xen_vm vm;
xen_string_string_map *result;
xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
if (xen_vm_get_by_name_label(session, &vms, dom->name) && vms->size > 0) {
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;
break;
}
}
xen_vm_set_free(vms);
xen_string_string_map_free(result);
if (flag == 0) return -1;
return 0;
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
/*
* 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) && vms->size > 0) {
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;
}
if (vms) xen_vm_set_free(vms);
xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, "");
return -1;
}
static char *
xenapiDomainGetSchedulerType (virDomainPtr dom ATTRIBUTE_UNUSED, int *nparams)
{
char *result = NULL;
*nparams = 0;
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, /* domainAttachDeviceFlags */
NULL, /* domainDetachDevice */
NULL, /* domainDetachDeviceFlags */
xenapiDomainGetAutostart, /* domainGetAutostart */
xenapiDomainSetAutostart, /* domainSetAutostart */
xenapiDomainGetSchedulerType, /* domainGetSchedulerType */
NULL, /* domainGetSchedulerParameters */
NULL, /* domainSetSchedulerParameters */
NULL, /* domainMigratePrepare */
NULL, /* domainMigratePerform */
NULL, /* domainMigrateFinish */
NULL, /* domainBlockStats */
NULL, /* domainInterfaceStats */
NULL, /* domainMemoryStats */
NULL, /* domainBlockPeek */
NULL, /* domainMemoryPeek */
xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
xenapiNodeGetFreeMemory, /* getFreeMemory */
NULL, /* domainEventRegister */
NULL, /* domainEventDeregister */
NULL, /* domainMigratePrepare2 */
NULL, /* domainMigrateFinish2 */
NULL, /* nodeDeviceDettach */
NULL, /* nodeDeviceReAttach */
NULL, /* nodeDeviceReset */
NULL, /* domainMigratePrepareTunnel */
NULL, /* isEncrypted */
NULL, /* isSecure */
NULL, /* domainIsActive */
NULL, /* domainIsPersistent */
NULL, /* cpuCompare */
NULL, /* cpuBaseline */
NULL, /* domainGetJobInfo */
NULL, /* domainAbortJob */
};
/**
* 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->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;
}
/*
* xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c.
* Copyright (C) 2009, 2010 Citrix Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: 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__ */
/*
* xenapi_driver_private.h: Xen API driver's private header file.
* Copyright (C) 2009, 2010 Citrix Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Sharadha Prabhakar <sharadha.prabhakar@citrix.com>
*/
#ifndef __VIR_XENAPI_H__
# define __VIR_XENAPI_H__
# include <libxml/tree.h>
# include <xen/api/xen_common.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;
char *url;
int noVerify;
virCapsPtr caps;
};
#endif /* __VIR_XENAPI_H__ */
/*
* xenapi_utils.c: Xen API driver -- utils parts.
* Copyright (C) 2009, 2010 Citrix Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Sharadha Prabhakar <sharadha.prabhakar@citrix.com>
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <libxml/uri.h>
#include <xen/api/xen_all.h>
#include "internal.h"
#include "domain_conf.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "util.h"
#include "uuid.h"
#include "memory.h"
#include "buf.h"
#include "logging.h"
#include "qparams.h"
#include "xenapi_driver_private.h"
#include "xenapi_utils.h"
void
xenSessionFree(xen_session *session)
{
int i;
if (session->error_description != NULL) {
for (i = 0; i < session->error_description_count; i++)
VIR_FREE(session->error_description[i]);
VIR_FREE(session->error_description);
}
VIR_FREE(session->session_id);
VIR_FREE(session);
}
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)
return;
if (pos < 0 || pos > max_bits - 1)
VIR_WARN ("number in str %d exceeds cpumap's max bits %d", 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;
if (!((*strings)->contents[sz-1].key = strdup(key))) goto error;
if (!((*strings)->contents[sz-1].val = strdup(val))) goto error;
return 0;
error:
xen_string_string_map_free(*strings);
virReportOOMError();
return -1;
}
/* 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)
{
xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
if (buf == NULL) {
char *ret = returnErrorFromSession(session);
virReportErrorHelper(conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s"), ret);
xen_session_clear_error(session);
VIR_FREE(ret);
} else {
virReportErrorHelper(conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s"), buf);
}
}
/* creates network intereface for VM */
int
createVifNetwork (virConnectPtr conn, xen_vm vm, char *device,
char *bridge, char *mac)
{
xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
xen_vm xvm = NULL;
char *uuid = NULL;
xen_vm_get_uuid(session, &uuid, vm);
if (uuid) {
if (!xen_vm_get_by_uuid(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;
if (xen_network_get_all(session, &net_set)) {
for(cnt = 0; cnt < net_set->size; cnt++) {
if (xen_network_get_record(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(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(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")) {
char *boot_order = NULL;
if (!((*record)->hvm_boot_policy = strdup("BIOS order")))
goto error_cleanup;
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);
}
}
return 0;
error_cleanup:
virReportOOMError();
xen_vm_record_free(*record);
return -1;
}
/*
* xenapi_utils.h: Xen API driver -- utils header
* Copyright (C) 2009, 2010 Citrix Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Sharadha Prabhakar <sharadha.prabhakar@citrix.com>
*/
#ifndef __VIR_XENAPI_UTILS__
# define __VIR_XENAPI_UTILS__
# include <stdint.h>
# include <libxml/uri.h>
# include <xen/api/xen_all.h>
# include "internal.h"
# include "domain_conf.h"
# define NETWORK_DEVID_SIZE (12)
typedef uint64_t cpumap_t;
void
xenSessionFree(xen_session *session);
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__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册