]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Support for container related domain XML extensions
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 1 Aug 2008 13:31:37 +0000 (13:31 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 1 Aug 2008 13:31:37 +0000 (13:31 +0000)
ChangeLog
docs/libvirt.rng
src/domain_conf.c
src/domain_conf.h
tests/domainschemadata/domain-lxc-simple.xml [new file with mode: 0644]
tests/domainschematest [changed mode: 0644->0755]

index 45d7cfa8c34c4d2085ed2396c4445e1ad51497bf..89b6ef36c315ec0f395270967114d894eff41d0c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Fri Aug  1 13:57:00 BST 2008 Daniel P. Berrange <berrange@redhat.com>
+
+       * src/domain_conf.h, src/domain_conf.c, docs/libvirt.rng: Add
+       support for an <init> element in <os> block, and <filesystem>
+       device type, and 'exe' OS type.
+       * tests/domainschematest: Check domainschemadata directory for
+       XML files
+       * tests/domainschemadata/domain-lxc-simple.xml: Simple example
+       for LXC driver to validate
+
 Fri Aug  1 13:54:00 BST 2008 Daniel P. Berrange <berrange@redhat.com>
 
        * src/qemu_driver.c: Always set forward-delay even if zero because
index 045a9c2b7f6fc868ecd6627ef3c6b07aaa321de0..cd5d79866e03a5db7fe4c91e9eb3045b8f854175 100644 (file)
@@ -44,6 +44,7 @@
     <choice>
       <ref name='osxen'/>
       <ref name='oshvm'/>
+      <ref name='osexe'/>
     </choice>
   </define>
 
   </define>
 
 
+  <define name='osexe'>
+    <element name='os'>
+      <element name='type'>
+       <value>exe</value>
+      </element>
+      <interleave>
+       <optional>
+         <element name='init'>
+           <ref name='absFilePath'/>
+         </element>
+       </optional>
+      </interleave>
+    </element>
+  </define>
+
+
+
   <!--
       The Identifiers can be:
       - an optional id attribute with a number on the domain element
       <empty/>
     </element>
   </define>
+
+  <define name='filesystem'>
+    <element name='filesystem'>
+      <choice>
+        <group>
+          <attribute name='type'>
+           <value>file</value>
+          </attribute>
+         <interleave>
+           <element name='source'>
+             <attribute name='file'>
+               <ref name='absFilePath'/>
+             </attribute>
+             <empty/>
+           </element>
+            <ref name='filesystemtgt'/>
+         </interleave>
+        </group>
+        <group>
+          <attribute name='type'>
+           <value>block</value>
+         </attribute>
+         <interleave>
+           <element name='source'>
+             <attribute name='dev'>
+               <ref name='deviceName'/>
+             </attribute>
+             <empty/>
+           </element>
+            <ref name='filesystemtgt'/>
+         </interleave>
+        </group>
+        <group>
+          <attribute name='type'>
+           <value>mount</value>
+         </attribute>
+         <interleave>
+           <element name='source'>
+             <attribute name='dir'>
+               <ref name='absFilePath'/>
+             </attribute>
+             <empty/>
+           </element>
+            <ref name='filesystemtgt'/>
+         </interleave>
+        </group>
+        <group>
+          <attribute name='type'>
+           <value>template</value>
+         </attribute>
+         <interleave>
+           <element name='source'>
+             <attribute name='name'>
+               <ref name='genericName'/>
+             </attribute>
+             <empty/>
+           </element>
+            <ref name='filesystemtgt'/>
+         </interleave>
+        </group>
+      </choice>
+    </element>
+  </define>
+
+  <define name='filesystemtgt'>
+    <element name='target'>
+      <attribute name='dir'>
+       <ref name='absDirPath'/>
+      </attribute>
+      <empty/>
+    </element>
+  </define>
+
   <!--
       An interface description can either be of type bridge in which case
       it will use a bridging source, or of type ethernet which uses a device
          <choice>
            <ref name='graphic'/>
            <ref name='disk'/>
+           <ref name='filesystem'/>
            <ref name='interface'/>
            <ref name='console'/>
             <ref name='sound'/>
       <param name="pattern">/[a-zA-Z0-9_\.\+\-&amp;/%]+</param>
     </data>
   </define>
+  <define name='absDirPath'>
+    <data type='string'>
+      <param name="pattern">/[a-zA-Z0-9_\.\+\-&amp;/%]*</param>
+    </data>
+  </define>
   <define name='devicePath'>
     <data type='string'>
       <param name="pattern">/[a-zA-Z0-9_\+\-/%]+</param>
index 0e99ccc5e19fbcfad03213bee1e4527e2759937e..a844c82444f307446712e8663640cf0a98a735d4 100644 (file)
@@ -86,6 +86,12 @@ VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
               "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",
@@ -237,6 +243,18 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainFSDefFree(virDomainFSDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->src);
+    VIR_FREE(def->dst);
+
+    virDomainFSDefFree(def->next);
+    VIR_FREE(def);
+}
+
 void virDomainNetDefFree(virDomainNetDefPtr def)
 {
     if (!def)
@@ -345,6 +363,7 @@ void virDomainDefFree(virDomainDefPtr def)
     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 @@ void virDomainDefFree(virDomainDefPtr def)
     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);
@@ -625,6 +645,89 @@ 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;
+}
+
+
 static void virDomainNetRandomMAC(virDomainNetDefPtr def) {
     /* XXX there different vendor prefixes per hypervisor */
     def->mac[0] = 0x52;
@@ -1351,6 +1454,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
         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 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
         }
     }
 
-    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 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
                                                                    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;
         }
@@ -1651,6 +1769,23 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
     }
     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);
+
     /* analysis of the network devices */
     if ((n = virXPathNodeSet(conn, "./devices/interface", ctxt, &nodes)) < 0) {
         virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -2247,6 +2382,57 @@ virDomainDiskDefFormat(virConnectPtr conn,
     return 0;
 }
 
+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,
@@ -2527,6 +2713,7 @@ char *virDomainDefFormat(virConnectPtr conn,
     unsigned char *uuid;
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     virDomainDiskDefPtr disk;
+    virDomainFSDefPtr fs;
     virDomainNetDefPtr net;
     virDomainSoundDefPtr sound;
     virDomainInputDefPtr input;
@@ -2596,6 +2783,9 @@ char *virDomainDefFormat(virConnectPtr conn,
     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);
@@ -2671,6 +2861,13 @@ char *virDomainDefFormat(virConnectPtr conn,
         disk = disk->next;
     }
 
+    fs = def->fss;
+    while (fs) {
+        if (virDomainFSDefFormat(conn, &buf, fs) < 0)
+            goto cleanup;
+        fs = fs->next;
+    }
+
     net = def->nets;
     while (net) {
         if (virDomainNetDefFormat(conn, &buf, net) < 0)
index e2c513d3e00de8b8f1e52acf84e0c0d1bf4b3b9a..527dc712f2454c20dbfcd4bfb6066a23093394fa 100644 (file)
@@ -94,6 +94,28 @@ struct _virDomainDiskDef {
 };
 
 
+/* 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;
+};
+
+
 /* 5 different types of networking config */
 enum virDomainNetType {
     VIR_DOMAIN_NET_TYPE_USER,
@@ -262,6 +284,7 @@ struct _virDomainGraphicsDef {
 /* 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 @@ struct _virDomainDeviceDef {
     int type;
     union {
         virDomainDiskDefPtr disk;
+        virDomainFSDefPtr fs;
         virDomainNetDefPtr net;
         virDomainInputDefPtr input;
         virDomainSoundDefPtr sound;
@@ -318,6 +342,7 @@ struct _virDomainOSDef {
     char *machine;
     int nBootDevs;
     int bootDevs[VIR_DOMAIN_BOOT_LAST];
+    char *init;
     char *kernel;
     char *initrd;
     char *cmdline;
@@ -357,6 +382,7 @@ struct _virDomainDef {
 
     virDomainGraphicsDefPtr graphics;
     virDomainDiskDefPtr disks;
+    virDomainFSDefPtr fss;
     virDomainNetDefPtr nets;
     virDomainInputDefPtr inputs;
     virDomainSoundDefPtr sounds;
@@ -411,6 +437,7 @@ virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
 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);
@@ -484,6 +511,7 @@ VIR_ENUM_DECL(virDomainLifecycle)
 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)
diff --git a/tests/domainschemadata/domain-lxc-simple.xml b/tests/domainschemadata/domain-lxc-simple.xml
new file mode 100644 (file)
index 0000000..653bbc7
--- /dev/null
@@ -0,0 +1,20 @@
+<domain type='lxc'>
+    <name>demo</name>
+    <uuid>8369f1ac-7e46-e869-4ca5-759d51478066</uuid>
+    <os>
+        <type>exe</type>
+        <init>/sh</init>
+    </os>
+    <memory>500000</memory>
+    <devices>
+        <filesystem type='mount'>
+            <source dir='/root/container'/>
+            <target dir='/'/>
+        </filesystem>
+        <filesystem type='mount'>
+            <source dir='/home'/>
+            <target dir='/home'/>
+        </filesystem>
+        <console type='pty'/>
+    </devices>
+</domain>
old mode 100644 (file)
new mode 100755 (executable)
index 3924400..e410cdc
@@ -2,7 +2,7 @@
 
 test -z "$srcdir" && srcdir=`pwd`
 
-DOMAINDIRS="qemuxml2argvdata sexpr2xmldata xmconfigdata xml2sexprdata"
+DOMAINDIRS="domainschemadata qemuxml2argvdata sexpr2xmldata xmconfigdata xml2sexprdata"
 
 n=0
 f=0