[libvirt] [PATCH v3 04/21] LXC from native: migrate fstab and lxc.mount.entry

Cédric Bosdonnat cbosdonnat at suse.com
Wed Feb 5 14:10:02 UTC 2014


Tmpfs relative size and default 50% size values aren't supported as
we have no idea of the available memory at the conversion time.
---
 src/lxc/lxc_container.c                         |   2 +-
 src/lxc/lxc_container.h                         |   2 +
 src/lxc/lxc_native.c                            | 251 +++++++++++++++++++++++-
 tests/lxcconf2xmldata/lxcconf2xml-fstab.config  |  37 ++++
 tests/lxcconf2xmldata/lxcconf2xml-simple.config |   4 +-
 tests/lxcconf2xmldata/lxcconf2xml-simple.xml    |   9 +
 tests/lxcconf2xmltest.c                         |  60 +++---
 7 files changed, 336 insertions(+), 29 deletions(-)
 create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config

diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index c6bdc8c..f08dbc2 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -744,7 +744,7 @@ static const virLXCBasicMountInfo lxcBasicMounts[] = {
 };
 
 
-static bool lxcIsBasicMountLocation(const char *path)
+bool lxcIsBasicMountLocation(const char *path)
 {
     size_t i;
 
diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h
index e74a7d7..67292ab 100644
--- a/src/lxc/lxc_container.h
+++ b/src/lxc/lxc_container.h
@@ -71,4 +71,6 @@ virArch lxcContainerGetAlt32bitArch(virArch arch);
 
 int lxcContainerChown(virDomainDefPtr def, const char *path);
 
+bool lxcIsBasicMountLocation(const char *path);
+
 #endif /* LXC_CONTAINER_H */
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c
index 86d0dd3..acd68db 100644
--- a/src/lxc/lxc_native.c
+++ b/src/lxc/lxc_native.c
@@ -21,10 +21,13 @@
  */
 
 #include <config.h>
+#include <stdio.h>
 
 #include "internal.h"
+#include "lxc_container.h"
 #include "lxc_native.h"
 #include "util/viralloc.h"
+#include "util/virfile.h"
 #include "util/virlog.h"
 #include "util/virstring.h"
 #include "util/virconf.h"
@@ -33,7 +36,11 @@
 
 
 static virDomainFSDefPtr
-lxcCreateFSDef(int type, char *src, char* dst)
+lxcCreateFSDef(int type,
+               char *src,
+               char* dst,
+               bool readonly,
+               unsigned long long usage)
 {
     virDomainFSDefPtr def;
 
@@ -44,16 +51,124 @@ lxcCreateFSDef(int type, char *src, char* dst)
     def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH;
     def->src = src;
     def->dst = dst;
+    def->readonly = readonly;
+    def->usage = usage;
 
     return def;
 }
 
+typedef struct _lxcFstab lxcFstab;
+typedef lxcFstab *lxcFstabPtr;
+struct _lxcFstab {
+    lxcFstabPtr next;
+    char *src;
+    char *dst;
+    char *type;
+    char *options;
+};
+
+static void
+lxcFstabFree(lxcFstabPtr fstab)
+{
+    while (fstab) {
+        lxcFstabPtr next = NULL;
+        next = fstab->next;
+
+        VIR_FREE(fstab->src);
+        VIR_FREE(fstab->dst);
+        VIR_FREE(fstab->type);
+        VIR_FREE(fstab->options);
+        VIR_FREE(fstab);
+
+        fstab = next;
+    }
+}
+
+static char ** lxcStringSplit(const char *string)
+{
+    char *tmp;
+    size_t i;
+    size_t ntokens = 0;
+    char **parts;
+    char **result = NULL;
+
+    if (VIR_STRDUP(tmp, string) < 0)
+        return NULL;
+
+    /* Replace potential \t by a space */
+    for (i = 0; tmp[i]; i++) {
+        if (tmp[i] == '\t')
+            tmp[i] = ' ';
+    }
+
+    parts = virStringSplit(tmp, " ", 0);
+    for (i = 0; parts[i]; i++) {
+        if (STREQ(parts[i], ""))
+            continue;
+
+        if (VIR_EXPAND_N(result, ntokens, 1) < 0)
+            goto error;
+
+        if (VIR_STRDUP(result[ntokens-1], parts[i]) < 0)
+            goto error;
+    }
+
+    /* Append NULL element */
+    if (VIR_EXPAND_N(result, ntokens, 1) < 0)
+        goto error;
+
+    VIR_FREE(tmp);
+    virStringFreeList(parts);
+    return result;
+
+error:
+    VIR_FREE(tmp);
+    virStringFreeList(parts);
+    virStringFreeList(result);
+    return NULL;
+}
+
+static lxcFstabPtr
+lxcParseFstabLine(char *fstabLine)
+{
+    lxcFstabPtr fstab = NULL;
+    char **parts;
+
+    if (!fstabLine || VIR_ALLOC(fstab) < 0)
+        return NULL;
+
+    parts = lxcStringSplit(fstabLine);
+
+    if (!parts[0] || !parts[1] || !parts[2] || !parts[3])
+        goto error;
+
+    if (VIR_STRDUP(fstab->src, parts[0]) < 0 ||
+            VIR_STRDUP(fstab->dst, parts[1]) < 0 ||
+            VIR_STRDUP(fstab->type, parts[2]) < 0 ||
+            VIR_STRDUP(fstab->options, parts[3]) < 0)
+        goto error;
+
+    virStringFreeList(parts);
+
+    return fstab;
+
+error:
+    lxcFstabFree(fstab);
+    virStringFreeList(parts);
+    return NULL;
+}
+
 static int
-lxcAddFSDef(virDomainDefPtr def, int type, char *src, char *dst)
+lxcAddFSDef(virDomainDefPtr def,
+            int type,
+            char *src,
+            char *dst,
+            bool readonly,
+            unsigned long long usage)
 {
     virDomainFSDefPtr fsDef = NULL;
 
-    if (!(fsDef = lxcCreateFSDef(type, src, dst)))
+    if (!(fsDef = lxcCreateFSDef(type, src, dst, readonly, usage)))
         goto error;
 
     if (VIR_EXPAND_N(def->fss, def->nfss, 1) < 0)
@@ -86,7 +201,7 @@ lxcSetRootfs(virDomainDefPtr def,
         type = VIR_DOMAIN_FS_TYPE_BLOCK;
 
 
-    if (lxcAddFSDef(def, type, fssrc, fsdst) < 0)
+    if (lxcAddFSDef(def, type, fssrc, fsdst, false, 0) < 0)
         goto error;
 
     return 0;
@@ -97,6 +212,119 @@ error:
     return -1;
 }
 
+static int
+lxcConvertSize(const char *size, unsigned long long *value)
+{
+    char *unit = NULL;
+
+    /* Split the string into value and unit */
+    if (virStrToLong_ull(size, &unit, 10, value) < 0)
+        goto error;
+
+    if (STREQ(unit, "%")) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("can't convert relative size: '%s'"),
+                       size);
+        return -1;
+    } else {
+        if (virScaleInteger(value, unit, 1, ULLONG_MAX) < 0)
+            goto error;
+    }
+
+    return 0;
+
+error:
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("failed to convert size: '%s'"),
+                   size);
+    return -1;
+}
+
+static int
+lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab)
+{
+    char *src = NULL;
+    char *dst = NULL;
+    char **options = virStringSplit(fstab->options, ",", 0);
+    bool readonly;
+    int type = VIR_DOMAIN_FS_TYPE_MOUNT;
+    unsigned long long usage = 0;
+
+    if (fstab->dst[0] != '/') {
+        if (virAsprintf(&dst, "/%s", fstab->dst) < 0)
+            goto error;
+    } else {
+        if (VIR_STRDUP(dst, fstab->dst) < 0)
+            goto error;
+    }
+
+    /* Check that we don't add basic mounts */
+    if (lxcIsBasicMountLocation(dst)) {
+        VIR_FREE(dst);
+        return 0;
+    }
+
+    if (STREQ(fstab->type, "tmpfs")) {
+        char *sizeStr = NULL;
+        size_t i;
+        type = VIR_DOMAIN_FS_TYPE_RAM;
+
+        for (i = 0; options[i]; i++) {
+            if ((sizeStr = STRSKIP(options[i], "size="))) {
+                if (lxcConvertSize(sizeStr, &usage) < 0)
+                    goto error;
+                break;
+            }
+        }
+        if (!sizeStr) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("missing tmpfs size, set the size option"));
+            goto error;
+        }
+    } else {
+        if (VIR_STRDUP(src, fstab->src) < 0)
+            goto error;
+    }
+
+    /* Do we have ro in options? */
+    readonly = virStringArrayHasString(options, "ro");
+
+    if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0)
+        goto error;
+
+
+    return 1;
+
+error:
+    VIR_FREE(dst);
+    VIR_FREE(src);
+    virStringFreeList(options);
+    return -1;
+}
+
+static int
+lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data)
+{
+    int ret = 0;
+    lxcFstabPtr fstabLine;
+    virDomainDefPtr def = data;
+
+    /* We only care about lxc.mount.entry lines */
+    if (STRNEQ(name, "lxc.mount.entry"))
+        return 0;
+
+    fstabLine = lxcParseFstabLine(value->str);
+
+    if (!fstabLine)
+        return -1;
+
+    if (lxcAddFstabLine(def, fstabLine) < 0)
+        ret = -1;
+
+    lxcFstabFree(fstabLine);
+    return ret;
+}
+
 virDomainDefPtr
 lxcParseConfigString(const char *config)
 {
@@ -115,6 +343,7 @@ lxcParseConfigString(const char *config)
                        _("failed to generate uuid"));
         goto error;
     }
+
     vmdef->id = -1;
     vmdef->mem.max_balloon = 64 * 1024;
 
@@ -127,6 +356,8 @@ lxcParseConfigString(const char *config)
      * minimum required to make XML parsing pass */
     vmdef->maxvcpus = 1;
 
+    vmdef->nfss = 0;
+
     if (VIR_STRDUP(vmdef->os.type, "exe") < 0)
         goto error;
 
@@ -142,6 +373,18 @@ lxcParseConfigString(const char *config)
     if (lxcSetRootfs(vmdef, properties) < 0)
         goto error;
 
+    /* Look for fstab: we shouldn't have it */
+    if (virConfGetValue(properties, "lxc.mount")) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("lxc.mount found, use lxc.mount.entry lines instead"));
+        goto error;
+    }
+
+    /* Loop over lxc.mount.entry to add filesystem devices for them */
+    value = virConfGetValue(properties, "lxc.mount.entry");
+    if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0)
+        goto error;
+
     goto cleanup;
 
 error:
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-fstab.config b/tests/lxcconf2xmldata/lxcconf2xml-fstab.config
new file mode 100644
index 0000000..8c03c22
--- /dev/null
+++ b/tests/lxcconf2xmldata/lxcconf2xml-fstab.config
@@ -0,0 +1,37 @@
+# Template used to create this container: opensuse
+# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef
+
+lxc.network.type = veth
+lxc.network.flags = up
+lxc.network.link = virbr0
+lxc.network.hwaddr = 02:00:15:8f:05:c1
+lxc.network.name = eth0
+
+#remove next line if host DNS configuration should not be available to container
+lxc.mount = /var/lib/lxc/migrate_test/fstab
+lxc.rootfs = /var/lib/lxc/migrate_test/rootfs
+lxc.utsname = migrate_test
+lxc.autodev=1
+lxc.tty = 2
+lxc.pts = 1024
+lxc.cap.drop = sys_module mac_admin mac_override mknod
+
+# When using LXC with apparmor, uncomment the next line to run unconfined:
+#lxc.aa_profile = unconfined
+
+lxc.cgroup.devices.deny = a
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rwm
+lxc.cgroup.devices.allow = c 1:5 rwm
+# consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+lxc.cgroup.devices.allow = c 4:0 rwm
+lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config
index 12428bb..f75e8fc 100644
--- a/tests/lxcconf2xmldata/lxcconf2xml-simple.config
+++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config
@@ -8,13 +8,15 @@ lxc.network.hwaddr = 02:00:15:8f:05:c1
 lxc.network.name = eth0
 
 #remove next line if host DNS configuration should not be available to container
+lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
+lxc.mount.entry = sysfs sys sysfs defaults  0 0
+lxc.mount.entry = tmpfs run tmpfs size=8m,mode=0755,nodev,nosuid 0 0
 lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,ro 0 0
 lxc.rootfs = /var/lib/lxc/migrate_test/rootfs
 lxc.utsname = migrate_test
 lxc.autodev=1
 lxc.tty = 2
 lxc.pts = 1024
-lxc.mount = /var/lib/lxc/migrate_test/fstab
 lxc.cap.drop = sys_module mac_admin mac_override mknod
 
 # When using LXC with apparmor, uncomment the next line to run unconfined:
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml
index eebcb4e..fadbdca 100644
--- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml
+++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml
@@ -17,5 +17,14 @@
       <source dir='/var/lib/lxc/migrate_test/rootfs'/>
       <target dir='/'/>
     </filesystem>
+    <filesystem type='ram' accessmode='passthrough'>
+      <source usage='8192' units='KiB'/>
+      <target dir='/run'/>
+    </filesystem>
+    <filesystem type='mount' accessmode='passthrough'>
+      <source dir='/etc/resolv.conf'/>
+      <target dir='/etc/resolv.conf'/>
+      <readonly/>
+    </filesystem>
   </devices>
 </domain>
diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c
index 9a840f9..c4b21ec 100644
--- a/tests/lxcconf2xmltest.c
+++ b/tests/lxcconf2xmltest.c
@@ -18,7 +18,8 @@ blankProblemElements(char *data)
 
 static int
 testCompareXMLToConfigFiles(const char *xml,
-                            const char *configfile)
+                            const char *configfile,
+                            bool expectError)
 {
     int ret = -1;
     char *config = NULL;
@@ -28,22 +29,26 @@ testCompareXMLToConfigFiles(const char *xml,
 
     if (virtTestLoadFile(configfile, &config) < 0)
         goto fail;
-    if (virtTestLoadFile(xml, &expectxml) < 0)
-        goto fail;
 
-    if (!(vmdef = lxcParseConfigString(config)))
+    vmdef = lxcParseConfigString(config);
+    if ((vmdef && expectError) || (!vmdef && !expectError))
         goto fail;
 
-    if (!(actualxml = virDomainDefFormat(vmdef, 0)))
-        goto fail;
+    if (vmdef) {
+        if (!(actualxml = virDomainDefFormat(vmdef, 0)))
+            goto fail;
 
-    if (blankProblemElements(expectxml) < 0 ||
-        blankProblemElements(actualxml) < 0)
-        goto fail;
+        if (virtTestLoadFile(xml, &expectxml) < 0)
+            goto fail;
 
-    if (STRNEQ(expectxml, actualxml)) {
-        virtTestDifference(stderr, expectxml, actualxml);
-        goto fail;
+        if (blankProblemElements(expectxml) < 0 ||
+            blankProblemElements(actualxml) < 0)
+            goto fail;
+
+        if (STRNEQ(expectxml, actualxml)) {
+            virtTestDifference(stderr, expectxml, actualxml);
+            goto fail;
+        }
     }
 
     ret = 0;
@@ -56,21 +61,26 @@ fail:
     return ret;
 }
 
+struct testInfo {
+    const char *name;
+    bool expectError;
+};
+
 static int
 testCompareXMLToConfigHelper(const void *data)
 {
     int result = -1;
-    const char *name = data;
+    const struct testInfo *info = data;
     char *xml = NULL;
     char *config = NULL;
 
     if (virAsprintf(&xml, "%s/lxcconf2xmldata/lxcconf2xml-%s.xml",
-                    abs_srcdir, name) < 0 ||
+                    abs_srcdir, info->name) < 0 ||
         virAsprintf(&config, "%s/lxcconf2xmldata/lxcconf2xml-%s.config",
-                    abs_srcdir, name) < 0)
+                    abs_srcdir, info->name) < 0)
         goto cleanup;
 
-    result = testCompareXMLToConfigFiles(xml, config);
+    result = testCompareXMLToConfigFiles(xml, config, info->expectError);
 
 cleanup:
     VIR_FREE(xml);
@@ -83,13 +93,17 @@ mymain(void)
 {
     int ret = EXIT_SUCCESS;
 
-# define DO_TEST(name)                                  \
-    if (virtTestRun("LXC Native-2-XML " name,           \
-                    testCompareXMLToConfigHelper,       \
-                    name) < 0)                          \
-        ret = EXIT_FAILURE
-
-    DO_TEST("simple");
+# define DO_TEST(name, expectError)                         \
+    do {                                                    \
+        const struct testInfo info = { name, expectError }; \
+        if (virtTestRun("LXC Native-2-XML " name,           \
+                        testCompareXMLToConfigHelper,       \
+                        &info) < 0)                         \
+            ret = EXIT_FAILURE;                             \
+    } while (0)
+
+    DO_TEST("simple", false);
+    DO_TEST("fstab", true);
 
     return ret;
 }
-- 
1.8.5.2




More information about the libvir-list mailing list