From 166d499f028a278265865fe9ae476514ccdbd492 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 14 Dec 2006 01:56:14 +0000 Subject: [PATCH] Implement support for inactive domains from Xen 3.0.4 --- ChangeLog | 14 ++- src/internal.h | 1 + src/xend_internal.c | 274 +++++++++++++++++++++++++++++++++++--------- src/xend_internal.h | 8 +- src/xm_internal.c | 9 +- 5 files changed, 242 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5112d1c7e9..f52cead3d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,16 @@ -Thu Dec 12 09:05:03 EST 2006 Daniel Berrange +Wed Dec 13 17:24:03 EST 2006 Daniel Berrange + + * src/xend_internal.c: Implement the ListDefinedDomains, NumOfDefinedDomains, + DomainCreate ,DomainDefineXML, DomainUndefine APIs to manage inactive domains + when running with Xen 3.0.4. Make GetMaxMemory, SetMaxMemory, SetMemory, + GetInfo, SetVCPUs & DumpXML work with inactive domains. Cache xendConfigVersion + when first connecting to Xend. + * src/xend_internal.h: Prototypes for new APIs + * src/xm_internal.c: Updated for new way of getting xendConfigVersion + data + * src/internal.h: Added xendConfigVersion field for virConnect struct + +Tue Dec 12 09:05:03 EST 2006 Daniel Berrange * src/xend_internal.c: Added support for vnclisten parameter in generated XML diff --git a/src/internal.h b/src/internal.h index c8a284a6b9..9b94b27381 100644 --- a/src/internal.h +++ b/src/internal.h @@ -108,6 +108,7 @@ struct _virConnect { int handle; /* internal handle used for hypercall */ struct xs_handle *xshandle;/* handle to talk to the xenstore */ int proxy; /* file descriptor if using the proxy */ + int xendConfigVersion; /* XenD config version */ /* connection to xend */ int type; /* PF_UNIX or PF_INET */ diff --git a/src/xend_internal.c b/src/xend_internal.c index 3cf1dd6fa8..ee630aeecd 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -41,6 +41,8 @@ static const char * xenDaemonGetType(virConnectPtr conn); static int xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids); static int xenDaemonNumOfDomains(virConnectPtr conn); +static int xenDaemonListDefinedDomains(virConnectPtr conn, const char **names, int maxnames); +static int xenDaemonNumOfDefinedDomains(virConnectPtr conn); static virDomainPtr xenDaemonLookupByID(virConnectPtr conn, int id); static virDomainPtr xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid); @@ -93,11 +95,11 @@ static virDriver xenDaemonDriver = { xenDaemonDomainPinVcpu, /* domainPinVcpu */ xenDaemonDomainGetVcpus, /* domainGetVcpus */ xenDaemonDomainDumpXML, /* domainDumpXML */ - NULL, /* listDefinedDomains */ - NULL, /* numOfDefinedDomains */ - NULL, /* domainCreate */ - NULL, /* domainDefineXML */ - NULL, /* domainUndefine */ + xenDaemonListDefinedDomains, /* listDefinedDomains */ + xenDaemonNumOfDefinedDomains, /* numOfDefinedDomains */ + xenDaemonDomainCreate, /* domainCreate */ + xenDaemonDomainDefineXML, /* domainDefineXML */ + xenDaemonDomainUndefine, /* domainUndefine */ xenDaemonAttachDevice, /* domainAttachDevice */ xenDaemonDetachDevice /* domainDetachDevice */ }; @@ -702,6 +704,7 @@ sexpr_int(struct sexpr *sexpr, const char *name) return 0; } + /** * sexpr_float: * @sexpr: an S-Expression @@ -1273,8 +1276,8 @@ xend_get_node(virConnectPtr xend) return node; } -int -xend_get_config_version(virConnectPtr conn) { +static int +xend_detect_config_version(virConnectPtr conn) { struct sexpr *root; const char *value; @@ -1286,23 +1289,20 @@ xend_get_config_version(virConnectPtr conn) { root = sexpr_get(conn, "/xend/node/"); if (root == NULL) return (-1); - + value = sexpr_node(root, "node/xend_config_format"); - + if (value) { - int version = strtol(value, NULL, 10); - sexpr_free(root); - return version; - } - + conn->xendConfigVersion = strtol(value, NULL, 10); + } else { + /* Xen prior to 3.0.3 did not have the xend_config_format + field, and is implicitly version 1. */ + conn->xendConfigVersion = 1; + } sexpr_free(root); - - /* Xen prior to 3.0.3 did not have the xend_config_format - field, and is implicitly version 1. */ - return 1; + return conn->xendConfigVersion; } - #ifndef PROXY /** * xend_node_shutdown: @@ -1853,7 +1853,7 @@ xend_parse_domain_sexp(virConnectPtr conn, char *sexpr, int xendConfigVersion) { * Returns 0 in case of success, -1 in case of error */ static int -sexpr_to_xend_domain_info(struct sexpr *root, virDomainInfoPtr info) +sexpr_to_xend_domain_info(virDomainPtr domain, struct sexpr *root, virDomainInfoPtr info) { const char *flags; @@ -1879,7 +1879,12 @@ sexpr_to_xend_domain_info(struct sexpr *root, virDomainInfoPtr info) else if (strchr(flags, 'r')) info->state = VIR_DOMAIN_RUNNING; } else { - info->state = VIR_DOMAIN_NOSTATE; + /* Inactive domains don't have a state reported, so + mark them SHUTOFF, rather than NOSTATE */ + if (domain->handle < 0) + info->state = VIR_DOMAIN_SHUTOFF; + else + info->state = VIR_DOMAIN_NOSTATE; } info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000; info->nrVirtCpu = sexpr_int(root, "domain/vcpus"); @@ -1940,6 +1945,7 @@ sexpr_to_domain(virConnectPtr conn, struct sexpr *root) char *dst_uuid = NULL; char uuid[16]; const char *name; + const char *tmp; if ((conn == NULL) || (root == NULL)) return(NULL); @@ -1954,12 +1960,20 @@ sexpr_to_domain(virConnectPtr conn, struct sexpr *root) ret = virGetDomain(conn, name, (const unsigned char *) &uuid[0]); if (ret == NULL) { virXendError(conn, VIR_ERR_NO_MEMORY, _("allocating domain")); - return(NULL); + return(NULL); } - ret->handle = sexpr_int(root, "domain/domid"); - if (ret->handle < 0) + tmp = sexpr_node(root, "domain/domid"); + /* New 3.0.4 XenD will not report a domid for inactive domains, + * so only error out for old XenD + */ + if (!tmp && conn->xendConfigVersion < 3) goto error; + if (tmp) + ret->handle = sexpr_int(root, "domain/domid"); + else + ret->handle = -1; /* An inactive domain */ + return (ret); error: @@ -2062,6 +2076,15 @@ try_http: } done: + /* The XenD config version is used to determine + * which APIs / features to activate. Lookup & cache + * it now to avoid repeated HTTP calls + */ + if (xend_detect_config_version(conn) < 0) { + virXendError(conn, VIR_ERR_INTERNAL_ERROR, "cannot determine xend config version"); + goto failed; + } + if (uri != NULL) xmlFreeURI(uri); return(ret); @@ -2302,7 +2325,7 @@ xenDaemonDomainGetMaxMemory(virDomainPtr domain) __FUNCTION__); return(-1); } - if (domain->handle < 0) + if (domain->handle < 0 && domain->conn->xendConfigVersion < 3) return(-1); /* can we ask for a subset ? worth it ? */ @@ -2338,7 +2361,7 @@ xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) __FUNCTION__); return(-1); } - if (domain->handle < 0) + if (domain->handle < 0 && domain->conn->xendConfigVersion < 3) return(-1); snprintf(buf, sizeof(buf), "%lu", memory >> 10); @@ -2372,7 +2395,7 @@ xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory) __FUNCTION__); return(-1); } - if (domain->handle < 0) + if (domain->handle < 0 && domain->conn->xendConfigVersion < 3) return(-1); snprintf(buf, sizeof(buf), "%lu", memory >> 10); @@ -2382,23 +2405,36 @@ xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory) #endif /* ! PROXY */ +/* XXX change proxy to use Name instead of ID, then + dumpxml will work over proxy for inactive domains + and this can be removed */ char * xenDaemonDomainDumpXMLByID(virConnectPtr conn, int domid) { char *ret = NULL; struct sexpr *root; - int xendConfigVersion; root = sexpr_get(conn, "/xend/domain/%d?detail=1", domid); if (root == NULL) return (NULL); - if ((xendConfigVersion = xend_get_config_version(conn)) < 0) { - virXendError(conn, VIR_ERR_INTERNAL_ERROR, "cannot determine xend config version"); - return (NULL); - } + ret = xend_parse_sexp_desc(conn, root, conn->xendConfigVersion); + sexpr_free(root); - ret = xend_parse_sexp_desc(conn, root, xendConfigVersion); + return (ret); +} + +char * +xenDaemonDomainDumpXMLByName(virConnectPtr conn, const char *name) +{ + char *ret = NULL; + struct sexpr *root; + + root = sexpr_get(conn, "/xend/domain/%s?detail=1", name); + if (root == NULL) + return (NULL); + + ret = xend_parse_sexp_desc(conn, root, conn->xendConfigVersion); sexpr_free(root); return (ret); @@ -2423,10 +2459,12 @@ xenDaemonDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED) __FUNCTION__); return(NULL); } - if (domain->handle < 0) + if (domain->handle < 0 && domain->conn->xendConfigVersion < 3) return(NULL); - - return xenDaemonDomainDumpXMLByID(domain->conn, domain->handle); + if (domain->handle < 0) + return xenDaemonDomainDumpXMLByName(domain->conn, domain->name); + else + return xenDaemonDomainDumpXMLByID(domain->conn, domain->handle); } #endif /* !PROXY */ @@ -2452,14 +2490,14 @@ xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) __FUNCTION__); return(-1); } - if (domain->handle < 0) + if (domain->handle < 0 && domain->conn->xendConfigVersion < 3) return(-1); root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name); if (root == NULL) return (-1); - ret = sexpr_to_xend_domain_info(root, info); + ret = sexpr_to_xend_domain_info(domain, root, info); sexpr_free(root); return (ret); } @@ -2484,8 +2522,9 @@ xenDaemonDomainLookupByName(virConnectPtr conn, const char *domname) if ((conn == NULL) || (domname == NULL)) { virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); - return(NULL); + return(NULL); } + root = sexpr_get(conn, "/xend/domain/%s?detail=1", domname); if (root == NULL) goto error; @@ -2735,7 +2774,7 @@ xenDaemonDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) __FUNCTION__); return (-1); } - if (domain->handle < 0) + if (domain->handle < 0 && domain->conn->xendConfigVersion < 3) return(-1); snprintf(buf, sizeof(buf), "%d", vcpus); @@ -2955,7 +2994,6 @@ xenDaemonCreateLinux(virConnectPtr conn, const char *xmlDesc, char *sexpr; char *name = NULL; virDomainPtr dom; - int xendConfigVersion; if (!VIR_IS_CONNECT(conn)) { virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); @@ -2966,13 +3004,7 @@ xenDaemonCreateLinux(virConnectPtr conn, const char *xmlDesc, return (NULL); } - if ((xendConfigVersion = xend_get_config_version(conn)) < 0) { - virXendError(conn, VIR_ERR_INTERNAL_ERROR, - "cannot determine xend config version"); - return (NULL); - } - - sexpr = virDomainParseXMLDesc(xmlDesc, &name, xendConfigVersion); + sexpr = virDomainParseXMLDesc(xmlDesc, &name, conn->xendConfigVersion); if ((sexpr == NULL) || (name == NULL)) { virXendError(conn, VIR_ERR_XML_ERROR, "domain"); if (sexpr != NULL) @@ -3032,21 +3064,17 @@ static int xenDaemonAttachDevice(virDomainPtr domain, char *xml) { char *sexpr, *conf; - int xendConfigVersion, hvm = 0, ret; + int hvm = 0, ret; if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, __FUNCTION__); return (-1); } - if ((xendConfigVersion = xend_get_config_version(domain->conn)) < 0) { - virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, - "cannot determine xend config version"); - return (-1); - } + if (strcmp(virDomainGetOSType(domain), "linux")) hvm = 1; - sexpr = virParseXMLDevice(xml, hvm, xendConfigVersion); + sexpr = virParseXMLDevice(xml, hvm, domain->conn->xendConfigVersion); if (sexpr == NULL) return (-1); if (!memcmp(sexpr, "(device ", 8)) { @@ -3084,8 +3112,144 @@ xenDaemonDetachDevice(virDomainPtr domain, char *xml) return(xend_op(domain->conn, domain->name, "op", "device_destroy", "type", class, "dev", ref, NULL)); } + + +virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) { + int ret; + char *sexpr; + char *name = NULL; + virDomainPtr dom; + + if (!VIR_IS_CONNECT(conn)) { + virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (xmlDesc == NULL) { + virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + sexpr = virDomainParseXMLDesc(xmlDesc, &name, conn->xendConfigVersion); + if ((sexpr == NULL) || (name == NULL)) { + virXendError(conn, VIR_ERR_XML_ERROR, "domain"); + if (sexpr != NULL) + free(sexpr); + if (name != NULL) + free(name); + + return (NULL); + } + + ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL); + free(sexpr); + if (ret != 0) { + fprintf(stderr, _("Failed to create inactive domain %s\n"), name); + goto error; + } + + dom = virDomainLookupByName(conn, name); + if (dom == NULL) { + goto error; + } + + return (dom); + error: + if (name != NULL) + free(name); + return (NULL); +} +int xenDaemonDomainCreate(virDomainPtr domain) { + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return(-1); + } + if (domain->conn->xendConfigVersion < 3) + return(-1); + + return xend_op(domain->conn, domain->name, "op", "start", NULL); +} + +int xenDaemonDomainUndefine(virDomainPtr domain) { + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return(-1); + } + if (domain->conn->xendConfigVersion < 3) + return(-1); + + return xend_op(domain->conn, domain->name, "op", "delete", NULL); +} + +/** + * xenDaemonNumOfDomains: + * @conn: pointer to the hypervisor connection + * + * Provides the number of active domains. + * + * Returns the number of domain found or -1 in case of error + */ +static int +xenDaemonNumOfDefinedDomains(virConnectPtr conn) +{ + struct sexpr *root = NULL; + int ret = -1; + struct sexpr *_for_i, *node; + + root = sexpr_get(conn, "/xend/domain?state=halted"); + if (root == NULL) + goto error; + + ret = 0; + + for (_for_i = root, node = root->car; _for_i->kind == SEXPR_CONS; + _for_i = _for_i->cdr, node = _for_i->car) { + if (node->kind != SEXPR_VALUE) + continue; + ret++; + } + +error: + if (root != NULL) + sexpr_free(root); + return(ret); +} + +int xenDaemonListDefinedDomains(virConnectPtr conn, const char **names, int maxnames) { + struct sexpr *root = NULL; + int ret = -1; + struct sexpr *_for_i, *node; + + if ((names == NULL) || (maxnames <= 0)) + goto error; + root = sexpr_get(conn, "/xend/domain?state=halted"); + if (root == NULL) + goto error; + + ret = 0; + + for (_for_i = root, node = root->car; _for_i->kind == SEXPR_CONS; + _for_i = _for_i->cdr, node = _for_i->car) { + if (node->kind != SEXPR_VALUE) + continue; + + names[ret++] = strdup(node->value); + if (ret >= maxnames) + break; + } + +error: + if (root != NULL) + sexpr_free(root); + return(ret); +} + #endif /* ! PROXY */ + + + /* * Local variables: * indent-tabs-mode: nil diff --git a/src/xend_internal.h b/src/xend_internal.h index 8f2197754f..95daf9087d 100644 --- a/src/xend_internal.h +++ b/src/xend_internal.h @@ -551,6 +551,9 @@ int xenDaemonDomainLookupByID(virConnectPtr xend, char *xenDaemonDomainDumpXMLByID(virConnectPtr xend, int domid); +char *xenDaemonDomainDumpXMLByName(virConnectPtr xend, + const char *name); + /** * \brief Lookup information about the host machine * \param xend A xend instance @@ -613,7 +616,6 @@ char *xenDaemonDomainDumpXMLByID(virConnectPtr xend, */ int xend_log(virConnectPtr xend, char *buffer, size_t n_buffer); - int xend_get_config_version(virConnectPtr conn); char *xend_parse_domain_sexp(virConnectPtr conn, char *root, int xendConfigVersion); /* refactored ones */ @@ -637,6 +639,10 @@ virDomainPtr xenDaemonDomainLookupByName(virConnectPtr conn, const char *domname unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain); char **xenDaemonListDomainsOld(virConnectPtr xend); +virDomainPtr xenDaemonDomainDefineXML(virConnectPtr xend, const char *sexpr); +int xenDaemonDomainCreate(virDomainPtr domain); +int xenDaemonDomainUndefine(virDomainPtr domain); + int xenDaemonDomainSetVcpus (virDomainPtr domain, unsigned int vcpus); int xenDaemonDomainPinVcpu (virDomainPtr domain, diff --git a/src/xm_internal.c b/src/xm_internal.c index 530c6f8ec7..3665107226 100644 --- a/src/xm_internal.c +++ b/src/xm_internal.c @@ -994,7 +994,7 @@ virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn, int xenXMDomainCreate(virDomainPtr domain) { char *xml; char *sexpr; - int ret, xendConfigVersion; + int ret; unsigned char uuid[16]; if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { @@ -1011,12 +1011,7 @@ int xenXMDomainCreate(virDomainPtr domain) { if (!(xml = xenXMDomainDumpXML(domain, 0))) return (-1); - if ((xendConfigVersion = xend_get_config_version(domain->conn)) < 0) { - xenXMError(domain->conn, VIR_ERR_INTERNAL_ERROR, "cannot determine xend config version"); - return (-1); - } - - if (!(sexpr = virDomainParseXMLDesc(xml, NULL, xendConfigVersion))) { + if (!(sexpr = virDomainParseXMLDesc(xml, NULL, domain->conn->xendConfigVersion))) { free(xml); return (-1); }