So, my previous set of patches for inactive domain management deal with the problem for Xen 3.0.3 or earlier. In 3.0.4 we now have lifecycle management support, which means we no longer need to scan /etc/xen config files if running against a new XenD. We choose between Xend & scanning /etc/xen files based on the condition 'xendConfigVersion >= 3'. The attached patch adds 5 new entry points to xend_internal.c xenDaemonListDefinedDomains xenDaemonNumOfDefinedDomains xenDaemonDomainCreate xenDaemonDomainDefineXML xenDaemonDomainUndefine These let you enumerate inactive domains, define new ones, delete old ones. Secondly, the patch modifies a number of existing methods to work against inactive domains too. Previously they'd unconditionally pass if the domain id was < 0. Now, if xendConfigVersion is >= 3, then they will know that XenD supports inactive domains & thus work for inactive guests too. xenDaemonDomainGetMaxMemory xenDaemonDomainSetMaxMemory xenDaemonDomainSetMemory xenDaemonDomainGetInfo xenDaemonDomainSetVcpus xenDaemonDomainDumpXML The methods for setting mem,max memory & vcpu count all required further bug fixes to Xend which have been sent upstream & hopefully merged soon. Finally, the patch changes the xendConfigVersion to be lookedup just once when initially connecting to XenD. Since we need this version info very frequently now, it was causing too much unnneccessary overload calling it every time. internal.h | 1 xend_internal.c | 270 +++++++++++++++++++++++++++++++++++++++++++++----------- xend_internal.h | 8 + xm_internal.c | 9 - 4 files changed, 227 insertions(+), 61 deletions(-) Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Index: src/internal.h =================================================================== RCS file: /data/cvs/libvirt/src/internal.h,v retrieving revision 1.25 diff -u -p -r1.25 internal.h --- src/internal.h 16 Nov 2006 19:06:13 -0000 1.25 +++ src/internal.h 13 Dec 2006 20:17:24 -0000 @@ -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 */ Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.81 diff -u -p -r1.81 xend_internal.c --- src/xend_internal.c 13 Dec 2006 14:08:51 -0000 1.81 +++ src/xend_internal.c 13 Dec 2006 20:17:27 -0000 @@ -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 cha 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 co 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 con * 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 * 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, stru 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, stru 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); @@ -2338,7 +2361,7 @@ xenDaemonDomainSetMaxMemory(virDomainPtr __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 do __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 do #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"); + ret = xend_parse_sexp_desc(conn, root, conn->xendConfigVersion); + sexpr_free(root); + + 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, xendConfigVersion); + ret = xend_parse_sexp_desc(conn, root, conn->xendConfigVersion); sexpr_free(root); return (ret); @@ -2423,10 +2459,12 @@ xenDaemonDomainDumpXML(virDomainPtr doma __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 doma __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(virConnectPt 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 dom __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, 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, 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 domai 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 Index: src/xend_internal.h =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.h,v retrieving revision 1.27 diff -u -p -r1.27 xend_internal.h --- src/xend_internal.h 15 Nov 2006 21:03:35 -0000 1.27 +++ src/xend_internal.h 13 Dec 2006 20:17:27 -0000 @@ -551,6 +551,9 @@ int xenDaemonDomainLookupByID(virConnect 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(virConn */ 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 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, Index: src/xm_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xm_internal.c,v retrieving revision 1.3 diff -u -p -r1.3 xm_internal.c --- src/xm_internal.c 22 Nov 2006 17:48:29 -0000 1.3 +++ src/xm_internal.c 13 Dec 2006 20:17:28 -0000 @@ -994,7 +994,7 @@ virDomainPtr xenXMDomainLookupByUUID(vir 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 domai 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); }