[Libvir] [PATCH] Inactive domain management for Xen 3.0.4

Daniel P. Berrange berrange at redhat.com
Wed Dec 13 20:32:13 UTC 2006


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  -=| 
-------------- next part --------------
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);
     }


More information about the libvir-list mailing list