[libvirt] PATCH: Support container XML enhancements

Daniel P. Berrange berrange at redhat.com
Tue Jul 29 15:20:14 UTC 2008


This is something I previously submitted as part of one of the LXC
patches, but I figure it makes sense on its own, since OpenVZ needs
this now too.

This adds two new XML elements to the domain XML format:

 - An <init> block within <os> allowing specification of the path for
   a binary to run when starting the container - aka 'init' by any other
   name. First we also specify that all containers will use an OS
   type of 'exe' - as in executable - the container equivalent of 'hvm'

       <os>
         <type>exe</type>
         <init>/sbin/init</init>
       </os>

 - An <filesystem> element for specifying how the container's filesystem
   is to be provided. This can actually be useful for full-machine virt
   too such as KVM which have host filesystem pass-through. There are
   various ways to configure it:

   eg to use '/some/directory' as the root filesystem for a container

      <filesystem type='mount'>
         <source dir='/some/directory'/>
         <target dir='/'/>
      </filesystem>

   eg to use a template called 'fedora9web' as the root filesystem for
      a container

      <filesystem type='template'>
         <source name='fedora9web'/>
         <target dir='/'/>
      </filesystem>
   
   eg to use a file containing a filesystem as the root filesystem

      <filesystem type='file'>
      	 <source file='/some/file.img'/>
         <target dir='/'/>
      </filesystem>

   eg to use a disk partition or other block device (eg LVM) containing
      a filesystem as the root filesystem

      <filesystem type='block'>
      	 <source dev='/dev/VolGroup00/Fedora9Web'/>
         <target dir='/'/>
      </filesystem>


   If setting the root filesystem, the target path will be '/', some
   container based virt allows the host OS root filesystem to be 
   used in the guest, and merely specify additive mounts at specific
   locations, 

   eg to override just /home within a container

      <filesystem type='mount'>
         <source dir='/some/directory'/>
         <target dir='/home'/>
      </filesystem>


I believe this should satisfy all the OpenVZ, LXC and Linux-VServer
drivers' requirements around filesystems

Daniel

diff -r 5614da5fe9ef src/domain_conf.c
--- a/src/domain_conf.c	Fri Jul 25 15:38:46 2008 +0100
+++ b/src/domain_conf.c	Tue Jul 29 16:03:38 2008 +0100
@@ -86,6 +86,12 @@
               "virtio",
               "xen")
 
+VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
+              "mount",
+              "block",
+              "file",
+              "template")
+
 VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
               "user",
               "ethernet",
@@ -234,6 +240,18 @@
     VIR_FREE(def->driverType);
 
     virDomainDiskDefFree(def->next);
+    VIR_FREE(def);
+}
+
+void virDomainFSDefFree(virDomainFSDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->src);
+    VIR_FREE(def->dst);
+
+    virDomainFSDefFree(def->next);
     VIR_FREE(def);
 }
 
@@ -345,6 +363,7 @@
     virDomainGraphicsDefFree(def->graphics);
     virDomainInputDefFree(def->inputs);
     virDomainDiskDefFree(def->disks);
+    virDomainFSDefFree(def->fss);
     virDomainNetDefFree(def->nets);
     virDomainChrDefFree(def->serials);
     virDomainChrDefFree(def->parallels);
@@ -355,6 +374,7 @@
     VIR_FREE(def->os.type);
     VIR_FREE(def->os.arch);
     VIR_FREE(def->os.machine);
+    VIR_FREE(def->os.init);
     VIR_FREE(def->os.kernel);
     VIR_FREE(def->os.initrd);
     VIR_FREE(def->os.cmdline);
@@ -620,6 +640,89 @@
 
  error:
     virDomainDiskDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
+
+/* Parse the XML definition for a disk
+ * @param node XML nodeset to parse for disk definition
+ */
+static virDomainFSDefPtr
+virDomainFSDefParseXML(virConnectPtr conn,
+                       xmlNodePtr node) {
+    virDomainFSDefPtr def;
+    xmlNodePtr cur;
+    char *type = NULL;
+    char *source = NULL;
+    char *target = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+        return NULL;
+    }
+
+    type = virXMLPropString(node, "type");
+    if (type) {
+        if ((def->type = virDomainFSTypeFromString(type)) < 0) {
+            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("unknown filesystem type '%s'"), type);
+            goto error;
+        }
+    } else {
+        def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
+    }
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if ((source == NULL) &&
+                (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+
+                if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT)
+                    source = virXMLPropString(cur, "dir");
+                else if (def->type == VIR_DOMAIN_FS_TYPE_FILE)
+                    source = virXMLPropString(cur, "file");
+                else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK)
+                    source = virXMLPropString(cur, "dev");
+                else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
+                    source = virXMLPropString(cur, "name");
+            } else if ((target == NULL) &&
+                       (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+                target = virXMLPropString(cur, "dir");
+            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
+                def->readonly = 1;
+            }
+        }
+        cur = cur->next;
+    }
+
+    if (source == NULL) {
+        virDomainReportError(conn, VIR_ERR_NO_SOURCE,
+                             target ? "%s" : NULL, target);
+        goto error;
+    }
+
+    if (target == NULL) {
+        virDomainReportError(conn, VIR_ERR_NO_TARGET,
+                             source ? "%s" : NULL, source);
+        goto error;
+    }
+
+    def->src = source;
+    source = NULL;
+    def->dst = target;
+    target = NULL;
+
+cleanup:
+    VIR_FREE(type);
+    VIR_FREE(target);
+    VIR_FREE(source);
+
+    return def;
+
+ error:
+    virDomainFSDefFree(def);
     def = NULL;
     goto cleanup;
 }
@@ -1351,6 +1454,10 @@
         dev->type = VIR_DOMAIN_DEVICE_DISK;
         if (!(dev->data.disk = virDomainDiskDefParseXML(conn, node)))
             goto error;
+    } else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
+        dev->type = VIR_DOMAIN_DEVICE_FS;
+        if (!(dev->data.fs = virDomainFSDefParseXML(conn, node)))
+            goto error;
     } else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
         dev->type = VIR_DOMAIN_DEVICE_NET;
         if (!(dev->data.net = virDomainNetDefParseXML(conn, node)))
@@ -1560,7 +1667,21 @@
         }
     }
 
-    if (!def->os.bootloader) {
+    /*
+     * Booting options for different OS types....
+     *
+     *   - A bootloader (and optional kernel+initrd)  (xen)
+     *   - A kernel + initrd                          (xen)
+     *   - A boot device (and optional kernel+initrd) (hvm)
+     *   - An init script                             (exe)
+     */
+
+    if (STREQ(def->os.type, "exe")) {
+        def->os.init = virXPathString(conn, "string(./os/init[1])", ctxt);
+    }
+
+    if (STREQ(def->os.type, "xen") ||
+        STREQ(def->os.type, "hvm")) {
         def->os.kernel = virXPathString(conn, "string(./os/kernel[1])", ctxt);
         def->os.initrd = virXPathString(conn, "string(./os/initrd[1])", ctxt);
         def->os.cmdline = virXPathString(conn, "string(./os/cmdline[1])", ctxt);
@@ -1610,12 +1731,9 @@
                                                                    def->os.type,
                                                                    def->os.arch,
                                                                    type);
-        if (!emulator) {
-            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                                 "%s", _("unsupported guest type"));
-            goto error;
-        }
-        if (!(def->emulator = strdup(emulator))) {
+
+        if (emulator &&
+            !(def->emulator = strdup(emulator))) {
             virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
             goto error;
         }
@@ -1648,6 +1766,23 @@
                 ptr = ptr->next;
             }
         }
+    }
+    VIR_FREE(nodes);
+
+    /* analysis of the filesystems */
+    if ((n = virXPathNodeSet(conn, "./devices/filesystem", ctxt, &nodes)) < 0) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract filesystem devices"));
+        goto error;
+    }
+    for (i = n - 1 ; i >= 0 ; i--) {
+        virDomainFSDefPtr fs = virDomainFSDefParseXML(conn,
+                                                      nodes[i]);
+        if (!fs)
+            goto error;
+
+        fs->next = def->fss;
+        def->fss = fs;
     }
     VIR_FREE(nodes);
 
@@ -2202,6 +2337,57 @@
 }
 
 static int
+virDomainFSDefFormat(virConnectPtr conn,
+                     virBufferPtr buf,
+                     virDomainFSDefPtr def)
+{
+    const char *type = virDomainFSTypeToString(def->type);
+
+    if (!type) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected filesystem type %d"), def->type);
+        return -1;
+    }
+
+    virBufferVSprintf(buf,
+                      "    <filesystem type='%s'>\n",
+                      type);
+
+    if (def->src) {
+        switch (def->type) {
+        case VIR_DOMAIN_FS_TYPE_MOUNT:
+            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
+                                  def->src);
+            break;
+
+        case VIR_DOMAIN_FS_TYPE_BLOCK:
+            virBufferEscapeString(buf, "      <source dev='%s'/>\n",
+                                  def->src);
+            break;
+
+        case VIR_DOMAIN_FS_TYPE_FILE:
+            virBufferEscapeString(buf, "      <source file='%s'/>\n",
+                                  def->src);
+            break;
+
+        case VIR_DOMAIN_FS_TYPE_TEMPLATE:
+            virBufferEscapeString(buf, "      <source name='%s'/>\n",
+                                  def->src);
+        }
+    }
+
+    virBufferVSprintf(buf, "      <target dir='%s'/>\n",
+                      def->dst);
+
+    if (def->readonly)
+        virBufferAddLit(buf, "      <readonly/>\n");
+
+    virBufferAddLit(buf, "    </filesystem>\n");
+
+    return 0;
+}
+
+static int
 virDomainNetDefFormat(virConnectPtr conn,
                       virBufferPtr buf,
                       virDomainNetDefPtr def)
@@ -2479,6 +2665,7 @@
     unsigned char *uuid;
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     virDomainDiskDefPtr disk;
+    virDomainFSDefPtr fs;
     virDomainNetDefPtr net;
     virDomainSoundDefPtr sound;
     virDomainInputDefPtr input;
@@ -2548,6 +2735,9 @@
     else
         virBufferVSprintf(&buf, ">%s</type>\n", def->os.type);
 
+    if (def->os.init)
+        virBufferEscapeString(&buf, "    <init>%s</init>\n",
+                              def->os.init);
     if (def->os.loader)
         virBufferEscapeString(&buf, "    <loader>%s</loader>\n",
                               def->os.loader);
@@ -2621,6 +2811,13 @@
         if (virDomainDiskDefFormat(conn, &buf, disk) < 0)
             goto cleanup;
         disk = disk->next;
+    }
+
+    fs = def->fss;
+    while (fs) {
+        if (virDomainFSDefFormat(conn, &buf, fs) < 0)
+            goto cleanup;
+        fs = fs->next;
     }
 
     net = def->nets;
diff -r 5614da5fe9ef src/domain_conf.h
--- a/src/domain_conf.h	Fri Jul 25 15:38:46 2008 +0100
+++ b/src/domain_conf.h	Tue Jul 29 16:03:38 2008 +0100
@@ -91,6 +91,28 @@
     unsigned int shared : 1;
 
     virDomainDiskDefPtr next;
+};
+
+
+/* Two types of disk backends */
+enum virDomainFSType {
+    VIR_DOMAIN_FS_TYPE_MOUNT,   /* Better named 'bind' */
+    VIR_DOMAIN_FS_TYPE_BLOCK,
+    VIR_DOMAIN_FS_TYPE_FILE,
+    VIR_DOMAIN_FS_TYPE_TEMPLATE,
+
+    VIR_DOMAIN_FS_TYPE_LAST
+};
+
+typedef struct _virDomainFSDef virDomainFSDef;
+typedef virDomainFSDef *virDomainFSDefPtr;
+struct _virDomainFSDef {
+    int type;
+    char *src;
+    char *dst;
+    unsigned int readonly : 1;
+
+    virDomainFSDefPtr next;
 };
 
 
@@ -262,6 +284,7 @@
 /* Flags for the 'type' field in next struct */
 enum virDomainDeviceType {
     VIR_DOMAIN_DEVICE_DISK,
+    VIR_DOMAIN_DEVICE_FS,
     VIR_DOMAIN_DEVICE_NET,
     VIR_DOMAIN_DEVICE_INPUT,
     VIR_DOMAIN_DEVICE_SOUND,
@@ -273,6 +296,7 @@
     int type;
     union {
         virDomainDiskDefPtr disk;
+        virDomainFSDefPtr fs;
         virDomainNetDefPtr net;
         virDomainInputDefPtr input;
         virDomainSoundDefPtr sound;
@@ -318,6 +342,7 @@
     char *machine;
     int nBootDevs;
     int bootDevs[VIR_DOMAIN_BOOT_LAST];
+    char *init;
     char *kernel;
     char *initrd;
     char *cmdline;
@@ -357,6 +382,7 @@
 
     virDomainGraphicsDefPtr graphics;
     virDomainDiskDefPtr disks;
+    virDomainFSDefPtr fss;
     virDomainNetDefPtr nets;
     virDomainInputDefPtr inputs;
     virDomainSoundDefPtr sounds;
@@ -411,6 +437,7 @@
 void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
 void virDomainInputDefFree(virDomainInputDefPtr def);
 void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainFSDefFree(virDomainFSDefPtr def);
 void virDomainNetDefFree(virDomainNetDefPtr def);
 void virDomainChrDefFree(virDomainChrDefPtr def);
 void virDomainSoundDefFree(virDomainSoundDefPtr def);
@@ -481,6 +508,7 @@
 VIR_ENUM_DECL(virDomainDisk)
 VIR_ENUM_DECL(virDomainDiskDevice)
 VIR_ENUM_DECL(virDomainDiskBus)
+VIR_ENUM_DECL(virDomainFS)
 VIR_ENUM_DECL(virDomainNet)
 VIR_ENUM_DECL(virDomainChr)
 VIR_ENUM_DECL(virDomainSoundModel)

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list