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 | 245 +++++++++++++++++++++++- 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, 330 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..31c1194 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,113 @@ 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 +337,7 @@ lxcParseConfigString(const char *config) _("failed to generate uuid")); goto error; } + vmdef->id = -1; vmdef->mem.max_balloon = 64 * 1024; @@ -127,6 +350,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 +367,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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list