[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 5/5]: Export <device> when doing logical pool discovery



When doing logical pool discovery, it currently returns XML like:

<sources><source><name>myvg</name></source></sources>

However, for oVirt, we need to know the device name that corresponds to this
logical volume group as well.  Therefore, extend the
virStorageBackendLogicalFindPoolSources function to return this information as
well.  This required pretty much a complete rewrite of the discovery function,
since I needed to be able to add <device> sections to already existing XML
nodes.  For that reason, this code uses direct libxml2 tree API's to handle the
parsing and the adding of nodes where necessary.

Signed-off-by: Chris Lalancette <clalance redhat com>
diff -up ./src/storage_backend_logical.c.p4 ./src/storage_backend_logical.c
--- ./src/storage_backend_logical.c.p4	2008-10-21 15:01:50.000000000 +0200
+++ ./src/storage_backend_logical.c	2008-10-21 15:06:55.000000000 +0200
@@ -23,6 +23,8 @@
 
 #include <config.h>
 
+#include <libxml/xmlsave.h>
+
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <stdio.h>
@@ -255,31 +257,77 @@ virStorageBackendLogicalRefreshPoolFunc(
 
 
 static int
-virStorageBackendLogicalFindPoolSourcesFunc(virConnectPtr conn ATTRIBUTE_UNUSED,
+virStorageBackendLogicalFindPoolSourcesFunc(virConnectPtr conn,
                                             virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                             char **const groups,
                                             void *data)
 {
-    virStringList **rest = data;
-    virStringList *newItem;
-    const char *name = groups[0];
+    const char *const pvname = groups[0];
+    const char *const vgname = groups[1];
+    char *content;
+    xmlDoc *xml = data;
+    xmlNode *root;
+    xmlNode *device;
+    xmlNode *curr;
+    xmlNode *child;
+    xmlNode *topNode;
+    int vgmatch;
+
+    root = xmlDocGetRootElement(xml);
+    if (root == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Unexpected NULL root element"));
+        return -1;
+    }
 
-    /* Append new XML desc to list */
+    /*
+     * The idea here is to try to find this vgname in the current XML.  If it
+     * already exists, then we just add a new device section to it.  If it
+     * doesn't yet exist, then we create new <source><name>foo</name></source>,
+     * then add the device section to it.
+     */
+    topNode = NULL;
+    curr = root->children;
+    while (curr != NULL) {
+        child = curr->children;
+        while (child != NULL) {
+            content = (char *)xmlNodeGetContent(child);
+            vgmatch = STREQ(vgname, content);
+            free(content);
+            if (STREQ((char *)child->name, "name") && vgmatch) {
+                topNode = curr;
+                break;
+            }
+            child = child->next;
+        }
+        curr = curr->next;
+    }
 
-    if (VIR_ALLOC(newItem) != 0) {
-        virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("new xml desc"));
-        return -1;
+    if (topNode == NULL) {
+        topNode = xmlNewChild(root, NULL, BAD_CAST "source", NULL);
+        if (topNode == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                                  _("Failed to create new XML source child"));
+            return -1;
+        }
+        if (xmlNewChild(topNode, NULL, BAD_CAST "name", BAD_CAST vgname) == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                                  _("Failed to create new XML name child"));
+            return -1;
+        }
     }
 
-    if (asprintf(&newItem->val, "<source><name>%s</name></source>", name) <= 0) {
-        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("asprintf failed"));
-        VIR_FREE(newItem);
+    device = xmlNewChild(topNode, NULL, BAD_CAST "device", NULL);
+    if (device == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Failed to create new XML device child"));
+        return -1;
+    }
+    if (xmlSetNsProp(device, NULL, BAD_CAST "path", BAD_CAST pvname) == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Failed to add device XML path property"));
         return -1;
     }
-
-    newItem->len = strlen(newItem->val);
-    newItem->next = *rest;
-    *rest = newItem;
 
     return 0;
 }
@@ -290,36 +338,76 @@ virStorageBackendLogicalFindPoolSources(
                                         unsigned int flags ATTRIBUTE_UNUSED)
 {
     /*
-     * # vgs --noheadings -o vg_name
-     *   VolGroup00
-     *   VolGroup01
+     * # pvs --noheadings -o pv_name,vg_name
+     *   /dev/sdb
+     *   /dev/sdc VolGroup00
      */
     const char *regexes[] = {
-        "^\\s*(\\S+)\\s*$"
+        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
     };
     int vars[] = {
-        1
+        2
     };
-    virStringList *descs = NULL;
-    const char *prog[] = { VGS, "--noheadings", "-o", "vg_name", NULL };
+    const char *const prog[] = { PVS, "--noheadings", "-o", "pv_name,vg_name", NULL };
     int exitstatus;
-    char *retval = NULL;
-
+    xmlDoc *xml = NULL;
+    xmlNode *root;
+    xmlSaveCtxt *saveCtxt;
+    xmlBuffer *buffer;
+    char *output = NULL;
+
+    /* First setup the XML document */
+    xml = xmlNewDoc(NULL);
+    if (xml == NULL) {
+        virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s",
+                              _("Failed to create new XML document"));
+        return NULL;
+    }
+    root = xmlNewNode(NULL, BAD_CAST "sources");
+    if (root == NULL) {
+        virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s",
+                              _("Failed to create new XML source node"));
+        goto cleanup_doc;
+    }
+    xmlDocSetRootElement(xml, root);
+
+    /* Now run PVS and get the output */
     if (virStorageBackendRunProgRegex(conn, NULL, prog, 1, regexes, vars,
                                       virStorageBackendLogicalFindPoolSourcesFunc,
-                                      &descs, &exitstatus) < 0)
-        return NULL;
+                                      xml, &exitstatus) < 0)
+        goto cleanup_doc;
 
-    retval = virStringListJoin(descs, SOURCES_START_TAG, SOURCES_END_TAG, "\n");
-    if (retval == NULL) {
-        virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("retval"));
-        goto cleanup;
-    }
+    /* Finally dump the XML to a buffer, and return it */
+    buffer = xmlBufferCreate();
+    if (buffer == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Failed to allocate XML buffer"));
+        goto cleanup_doc;
+    }
+    saveCtxt = xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_DECL);
+    if (saveCtxt == NULL) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Failed to setup XML save buffer"));
+        goto free_buffer;
+    }
+    if (xmlSaveTree(saveCtxt, root) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Failed to save XML tree"));
+        xmlSaveClose(saveCtxt);
+        goto free_buffer;
+    }
+
+    /* NOTE: xmlSaveClose must be before xmlBufferContent so we flush */
+    xmlSaveClose(saveCtxt);
+    output = strdup((char *)xmlBufferContent(buffer));
 
- cleanup:
-    virStringListFree(descs);
+ free_buffer:
+    xmlBufferFree(buffer);
+
+ cleanup_doc:
+    xmlFreeDoc(xml);
 
-    return retval;
+    return output;
 }
 
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]