[libvirt] [PATCH 00/16] lxc driver connectDomainXMLFromNative

The aim of these patches is to provide users a way to easily convert existing LXC containers into libvirt LXC domains. This conversion is mostly based on the use of connectDomainXMLFromNative implementation, but there are small bits that will still need to be manually tweaked, like creating a VLAN interface on the host or precise the rootfs format for image files. Cédric Bosdonnat (16): LXC driver: started implementing connectDomainXMLFromNative LXC from native: import rootfs LXC from native: migrate fstab and lxc.mount.entry LXC from native: implement no network conversion LXC from native: migrate veth network configuration LXC from native: convert phys network types to net hostdev devices LXC from native: convert lxc.tty to console devices LXC from native: convert macvlan network configuration LXC from native: convert lxc.id_map into <idmap> LXC from native: migrate memory tuning LXC from native: map lxc.cgroup.cpu.* LXC from native: map lxc.cgroup.cpuset.* LXC from native: add lxc.cgroup.blkio.* mapping LXC from native: map lxc.arch to /domain/os/type@arch LXC from native: map block filesystems LXC from native: map vlan network type .gitignore | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_driver.c | 36 +- src/lxc/lxc_native.c | 1027 ++++++++++++++++++++ src/lxc/lxc_native.h | 34 + tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 9 + tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 44 + .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 8 + tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 36 + tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 9 + tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 38 + tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 32 + .../lxcconf2xml-macvlannetwork.config | 14 + .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 30 + tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 12 + tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 38 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 5 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 33 + .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 8 + tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 35 + tests/lxcconf2xmldata/lxcconf2xml-simple.config | 39 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 41 + .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 13 + tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 30 + tests/lxcconf2xmldata/lxcconf2xml.fstab | 3 + tests/lxcconf2xmltest.c | 133 +++ 31 files changed, 1724 insertions(+), 3 deletions(-) create mode 100644 src/lxc/lxc_native.c create mode 100644 src/lxc/lxc_native.h create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml.fstab create mode 100644 tests/lxcconf2xmltest.c -- 1.8.5.2

This function aims at converting LXC configuration into a libvirt domain XML description to help users migrate from LXC to libvirt. Here is an example of how the lxc configuration works: virsh -c lxc:/// domxml-from-native lxc /var/lib/lxc/migrate_test/config It is possible that some parts couldn't be properly mapped into a domain XML fragment, so users should carefully review the result before creating the domain. --- .gitignore | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_driver.c | 36 +++- src/lxc/lxc_native.c | 259 ++++++++++++++++++++++++ src/lxc/lxc_native.h | 34 ++++ tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-simple.config | 38 ++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 17 ++ tests/lxcconf2xmldata/lxcconf2xml.fstab | 3 + tests/lxcconf2xmltest.c | 124 ++++++++++++ 11 files changed, 519 insertions(+), 2 deletions(-) create mode 100644 src/lxc/lxc_native.c create mode 100644 src/lxc/lxc_native.h create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-simple.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml.fstab create mode 100644 tests/lxcconf2xmltest.c diff --git a/.gitignore b/.gitignore index 496c2ef..662cf8d 100644 --- a/.gitignore +++ b/.gitignore @@ -156,6 +156,7 @@ /tests/hashtest /tests/jsontest /tests/libvirtdconftest +/tests/lxcconf2xmltest /tests/metadatatest /tests/networkxml2argvtest /tests/nodeinfotest diff --git a/po/POTFILES.in b/po/POTFILES.in index 0359b2f..fd36bc5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -62,6 +62,7 @@ src/locking/sanlock_helper.c src/lxc/lxc_cgroup.c src/lxc/lxc_fuse.c src/lxc/lxc_hostdev.c +src/lxc/lxc_native.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index 57e163f..43df69f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -622,6 +622,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_monitor.c lxc/lxc_monitor.h \ lxc/lxc_process.c lxc/lxc_process.h \ lxc/lxc_fuse.c lxc/lxc_fuse.h \ + lxc/lxc_native.c lxc/lxc_native.h \ lxc/lxc_driver.c lxc/lxc_driver.h LXC_CONTROLLER_SOURCES = \ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 7e56a59..c10a722 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -44,6 +44,7 @@ #include "lxc_container.h" #include "lxc_domain.h" #include "lxc_driver.h" +#include "lxc_native.h" #include "lxc_process.h" #include "viralloc.h" #include "virnetdevbridge.h" @@ -73,7 +74,6 @@ #define VIR_FROM_THIS VIR_FROM_LXC - #define LXC_NB_MEM_PARAM 3 static int lxcStateInitialize(bool privileged, @@ -993,6 +993,39 @@ cleanup: return ret; } +static char *lxcConnectDomainXMLFromNative(virConnectPtr conn, + const char *nativeFormat, + const char *nativeConfig, + unsigned int flags) +{ + char *xml = NULL; + virDomainDefPtr def = NULL; + virNodeInfo nodeInfos; + + virCheckFlags(0, NULL); + + if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0) + goto cleanup; + + if (STRNEQ(nativeFormat, LXC_CONFIG_FORMAT)) { + virReportError(VIR_ERR_INVALID_ARG, + _("unsupported config type %s"), nativeFormat); + goto cleanup; + } + + if (nodeGetInfo(&nodeInfos) < 0) + goto cleanup; + + if (!(def = lxcParseConfigString(nativeConfig, NULL, nodeInfos.memory))) + goto cleanup; + + xml = virDomainDefFormat(def, 0); + +cleanup: + virDomainDefFree(def); + return xml; +} + /** * lxcDomainCreateWithFiles: * @dom: domain to start @@ -4760,6 +4793,7 @@ static virDriver lxcDriver = { .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */ .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */ .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */ + .connectDomainXMLFromNative = lxcConnectDomainXMLFromNative, /* 1.2.2 */ .connectListDefinedDomains = lxcConnectListDefinedDomains, /* 0.4.2 */ .connectNumOfDefinedDomains = lxcConnectNumOfDefinedDomains, /* 0.4.2 */ .domainCreate = lxcDomainCreate, /* 0.4.4 */ diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c new file mode 100644 index 0000000..14b2844 --- /dev/null +++ b/src/lxc/lxc_native.c @@ -0,0 +1,259 @@ +/* + * lxc_native.c: LXC native configuration import + * + * Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Cedric Bosdonnat <cbosdonnat@suse.com> + */ + +#include <config.h> + +#include "internal.h" +#include "lxc_native.h" +#include "util/viralloc.h" +#include "util/virlog.h" +#include "util/virstring.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +typedef struct _virPropertyEntry virPropertyEntry; +typedef virPropertyEntry *virPropertyEntryPtr; +struct _virPropertyEntry { + virPropertyEntry *next; + char *key; + char *value; +}; + +typedef struct { + virPropertyEntryPtr elements; + virPropertyEntryPtr last; + + /* Store the current item and key when looping */ + char *currentKey; + virPropertyEntryPtr current; +} virProperties; +typedef virProperties *virPropertiesPtr; + +static virPropertiesPtr +virPropertiesCreate(void) +{ + virPropertiesPtr properties = NULL; + + if (VIR_ALLOC(properties) < 0) + return NULL; + + properties->current = NULL; + properties->elements = NULL; + + return properties; +} + +static void +virPropertiesFree(virPropertiesPtr properties) +{ + virPropertyEntryPtr entry; + + if (!properties) + return; + + entry = properties->elements; + while (entry) { + virPropertyEntryPtr next = NULL; + next = entry->next; + + VIR_FREE(entry->key); + VIR_FREE(entry->value); + VIR_FREE(entry); + + entry = next; + } + + VIR_FREE(properties->currentKey); + VIR_FREE(properties); +} + +static int +virPropertiesAddEntry(virPropertiesPtr properties, char *key, char *value) +{ + virPropertyEntryPtr entry; + + if (!properties || !key) + return -1; + + if (VIR_ALLOC(entry) < 0) + return -1; + + entry->key = key; + entry->value = value; + entry->next = NULL; + + if (properties->last) + properties->last->next = entry; + if (!properties->elements) + properties->elements = entry; + + properties->last = entry; + + return 0; +} + +static char +*virPropertiesLookup(virPropertiesPtr properties, const char* key) +{ + if (!properties) + return NULL; + + /* If the key is not NULL, reset the search */ + if (key) { + properties->current = NULL; + VIR_FREE(properties->currentKey); + if (VIR_STRDUP(properties->currentKey, key) < 0) + return NULL; + } else if (!properties->currentKey) { + return NULL; + } + + if (!properties->current) + properties->current = properties->elements; + else + properties->current = properties->current->next; + + while (properties->current && STRNEQ(properties->current->key, properties->currentKey)) { + properties->current = properties->current->next; + } + + if (!properties->current) + return NULL; + + return properties->current->value; +} + +static char +*lxcSkipTrimSpaces(char *src) +{ + char *dest = NULL; + char *rawString = NULL; + const char* skipped; + + if (VIR_STRDUP(rawString, src) < 0) + return NULL; + + virTrimSpaces(rawString, NULL); + + skipped = rawString; + virSkipSpaces(&skipped); + + if (VIR_STRDUP(dest, skipped) < 0) + dest = NULL; + + VIR_FREE(rawString); + return dest; +} + +static virPropertiesPtr +lxcParseProperties(const char *properties) +{ + virPropertiesPtr table; + char **lines; + size_t i; + char *line; + char **lineParts; + char *key = NULL; + char *value = NULL; + + table = virPropertiesCreate(); + lines = virStringSplit(properties, "\n", 0); + + for (i = 0; lines[i]; i++) { + line = lines[i]; + + /* Ignore comment lines */ + if (line[0] == '#') + continue; + + /* Find key = value lines and skip other ones (bad or good) */ + lineParts = virStringSplit(line, "=", 2); + if (virStringListLength(lineParts) == 2) { + if (!(key = lxcSkipTrimSpaces(lineParts[0])) || + !(value = lxcSkipTrimSpaces(lineParts[1]))) + continue; + + if (virPropertiesAddEntry(table, key, value) < 0) + VIR_ERROR(_("Skipped lxc config entry: %s = %s"), + key, value); + } + virStringFreeList(lineParts); + } + + virStringFreeList(lines); + + return table; +} + +virDomainDefPtr +lxcParseConfigString(const char *config, + const char *fstab ATTRIBUTE_UNUSED, + unsigned long memory) +{ + virDomainDefPtr vmdef = NULL; + virPropertiesPtr properties = NULL; + + if (!(properties = lxcParseProperties(config))) + return NULL; + + if (VIR_ALLOC(vmdef) < 0) + goto error; + + if (virUUIDGenerate(vmdef->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to generate uuid")); + goto error; + } + vmdef->id = -1; + vmdef->mem.max_balloon = memory; + + vmdef->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART; + vmdef->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY; + vmdef->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY; + vmdef->virtType = VIR_DOMAIN_VIRT_LXC; + + /* Value not handled by the LXC driver, setting to + * minimum required to make XML parsing pass */ + vmdef->maxvcpus = 1; + + if (VIR_STRDUP(vmdef->os.type, "exe") < 0) + goto error; + + if (VIR_STRDUP(vmdef->os.init, "/sbin/init") < 0) + goto error; + + if (VIR_STRDUP(vmdef->name, virPropertiesLookup(properties, "lxc.utsname")) < 0) + goto error; + if (!vmdef->name && VIR_STRDUP(vmdef->name, "unnamed")) + goto error; + + goto cleanup; + +error: + virDomainDefFree(vmdef); + vmdef = NULL; + +cleanup: + virPropertiesFree(properties); + + return vmdef; +} diff --git a/src/lxc/lxc_native.h b/src/lxc/lxc_native.h new file mode 100644 index 0000000..448fc09 --- /dev/null +++ b/src/lxc/lxc_native.h @@ -0,0 +1,34 @@ +/* + * lxc_native.h: LXC native configuration import + * + * Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Cedric Bosdonnat <cbosdonnat@suse.com> + */ + +#ifndef __LXC_NATIVE_H__ +# define __LXC_NATIVE_H__ + +# include "domain_conf.h" + +# define LXC_CONFIG_FORMAT "lxc" + +virDomainDefPtr lxcParseConfigString(const char *config, + const char *fstab, + unsigned long memory); + +#endif /* __LXC_NATIVE_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 568b7a0..b597a90 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -196,7 +196,7 @@ test_programs += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \ endif WITH_QEMU if WITH_LXC -test_programs += lxcxml2xmltest +test_programs += lxcxml2xmltest lxcconf2xmltest endif WITH_LXC if WITH_OPENVZ @@ -508,6 +508,11 @@ lxcxml2xmltest_SOURCES = \ lxcxml2xmltest.c testutilslxc.c testutilslxc.h \ testutils.c testutils.h lxcxml2xmltest_LDADD = $(lxc_LDADDS) + +lxcconf2xmltest_SOURCES = \ + lxcconf2xmltest.c \ + testutils.c testutils.h +lxcconf2xmltest_LDADD = $(lxc_LDADDS) else ! WITH_LXC EXTRA_DIST += lxcxml2xmltest.c testutilslxc.c testutilslxc.h endif ! WITH_LXC diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config new file mode 100644 index 0000000..12428bb --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -0,0 +1,38 @@ +# 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.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: +#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.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml new file mode 100644 index 0000000..a277751 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -0,0 +1,17 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + </devices> +</domain> diff --git a/tests/lxcconf2xmldata/lxcconf2xml.fstab b/tests/lxcconf2xmldata/lxcconf2xml.fstab new file mode 100644 index 0000000..a08b2d6 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml.fstab @@ -0,0 +1,3 @@ +proc proc proc nodev,noexec,nosuid 0 0 +sysfs sys sysfs defaults 0 0 +tmpfs run tmpfs mode=0755,nodev,nosuid 0 0 diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c new file mode 100644 index 0000000..6f0f97e --- /dev/null +++ b/tests/lxcconf2xmltest.c @@ -0,0 +1,124 @@ +#include <config.h> + +#include "testutils.h" + +#ifdef WITH_LXC + +# include "lxc/lxc_native.h" + +# define VIR_FROM_THIS VIR_FROM_NONE + +# define LXC_TEST_MEMORY_AMOUNT 4035770ul + +static int +blankProblemElements(char *data) +{ + if (virtTestClearLineRegex("<uuid>([[:alnum:]]|-)+</uuid>", data) < 0) + return -1; + return 0; +} + +static int +testCompareXMLToConfigFiles(const char *xml, + const char *configfile, + const char *fstabfile, + const char *defaultFstab) +{ + int ret = -1; + char *config = NULL; + char *fstab = NULL; + char *expectxml = NULL; + char *actualxml = NULL; + virDomainDefPtr vmdef = NULL; + + if (virtTestLoadFile(configfile, &config) < 0) + goto fail; + if (virtTestLoadFile(fstabfile, &fstab) < 0 && + virtTestLoadFile(defaultFstab, &fstab) < 0) + goto fail; + if (virtTestLoadFile(xml, &expectxml) < 0) + goto fail; + + if (!(vmdef = lxcParseConfigString(config, fstab, LXC_TEST_MEMORY_AMOUNT))) + goto fail; + + if (!(actualxml = virDomainDefFormat(vmdef, 0))) + goto fail; + + if (blankProblemElements(expectxml) < 0 || + blankProblemElements(actualxml) < 0) + goto fail; + + if (STRNEQ(expectxml, actualxml)) { + virtTestDifference(stderr, expectxml, actualxml); + goto fail; + } + + ret = 0; + +fail: + VIR_FREE(expectxml); + VIR_FREE(actualxml); + VIR_FREE(config); + VIR_FREE(fstab); + virDomainDefFree(vmdef); + return ret; +} + +static int +testCompareXMLToConfigHelper(const void *data) +{ + int result = -1; + const char *name = data; + char *xml = NULL; + char *config = NULL; + char *fstab = NULL; + char *defaultFstab = NULL; + + if (virAsprintf(&xml, "%s/lxcconf2xmldata/lxcconf2xml-%s.xml", + abs_srcdir, name) < 0 || + virAsprintf(&config, "%s/lxcconf2xmldata/lxcconf2xml-%s.config", + abs_srcdir, name) < 0 || + virAsprintf(&fstab, "%s/lxcconf2xmldata/lxcconf2xml-%s.fstab", + abs_srcdir, name) < 0 || + virAsprintf(&defaultFstab, "%s/lxcconf2xmldata/lxcconf2xml.fstab", + abs_srcdir) < 0) + goto cleanup; + + result = testCompareXMLToConfigFiles(xml, config, fstab, defaultFstab); + +cleanup: + VIR_FREE(xml); + VIR_FREE(config); + VIR_FREE(fstab); + VIR_FREE(defaultFstab); + return result; +} + +static int +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"); + + return ret; +} + +VIRT_TEST_MAIN(mymain) + +#else + +int +main(void) +{ + return EXIT_AM_SKIP; +} + +#endif /* WITH_LXC */ -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:50PM +0100, Cédric Bosdonnat wrote:
This function aims at converting LXC configuration into a libvirt domain XML description to help users migrate from LXC to libvirt.
Here is an example of how the lxc configuration works: virsh -c lxc:/// domxml-from-native lxc /var/lib/lxc/migrate_test/config
It is possible that some parts couldn't be properly mapped into a domain XML fragment, so users should carefully review the result before creating the domain. diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c new file mode 100644 index 0000000..14b2844 --- /dev/null +++ b/src/lxc/lxc_native.c
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config new file mode 100644 index 0000000..12428bb --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -0,0 +1,38 @@ +# 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.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: +#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
This data format looks really very close to the .vmx file format. The main difference I see is that the right hand side of the = sign does not require quotes. We already have a src/util/virconf.{c,h} module which was originally designed to parse Xen's python-like config files. It was then extended to cope with .vmx files. It seems like it should be easy to extend it to handle the lxc file format too. eg define a new VIR_CONF_FLAG_LXC_FORMAT flag for it parser to honour
diff --git a/tests/lxcconf2xmldata/lxcconf2xml.fstab b/tests/lxcconf2xmldata/lxcconf2xml.fstab new file mode 100644 index 0000000..a08b2d6 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml.fstab @@ -0,0 +1,3 @@ +proc proc proc nodev,noexec,nosuid 0 0 +sysfs sys sysfs defaults 0 0 +tmpfs run tmpfs mode=0755,nodev,nosuid 0 0
Hmm, how are the fstab files handled ? The virConnectDomainNativeToXML API only allows a single config file to be passed into ? Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Hi Dan, On Fri, 2014-01-24 at 13:17 +0000, Daniel P. Berrange wrote:
This data format looks really very close to the .vmx file format. The main difference I see is that the right hand side of the = sign does not require quotes.
We already have a src/util/virconf.{c,h} module which was originally designed to parse Xen's python-like config files. It was then extended to cope with .vmx files. It seems like it should be easy to extend it to handle the lxc file format too.
eg define a new VIR_CONF_FLAG_LXC_FORMAT flag for it parser to honour
Good to know... I wasn't aware of that. I'll have a look at it to share as much code as possible.
diff --git a/tests/lxcconf2xmldata/lxcconf2xml.fstab b/tests/lxcconf2xmldata/lxcconf2xml.fstab new file mode 100644 index 0000000..a08b2d6 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml.fstab @@ -0,0 +1,3 @@ +proc proc proc nodev,noexec,nosuid 0 0 +sysfs sys sysfs defaults 0 0 +tmpfs run tmpfs mode=0755,nodev,nosuid 0 0
Hmm, how are the fstab files handled ? The virConnectDomainNativeToXML API only allows a single config file to be passed into ?
I assumed we could get the fstab file from the config file corresponding entry. Of course for the unit tests I had to tweak that a bit. If we can't assume fstab can be fetched, then what could we do? -- Cedric

LXC rootfs can be either a directory or a block device or an image file. The first two types have been implemented, but the image file is still to be done since LXC auto-guesses the file format at mount time and the LXC driver doesn't support the 'auto' format. --- src/lxc/lxc_native.c | 70 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 74 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 14b2844..2cd9143 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -21,6 +21,7 @@ */ #include <config.h> +#include <sys/stat.h> #include "internal.h" #include "lxc_native.h" @@ -204,6 +205,72 @@ lxcParseProperties(const char *properties) return table; } +static virDomainFSDefPtr +lxcCreateFSDef(int type, char *src, char* dst) +{ + virDomainFSDefPtr def; + + if (VIR_ALLOC(def) < 0) + return NULL; + + def->type = type; + def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; + def->src = src; + def->dst = dst; + + return def; +} + +static int +lxcAddFSDef(virDomainDefPtr def, int type, char *src, char *dst) +{ + virDomainFSDefPtr fsDef = NULL; + + if (!(fsDef = lxcCreateFSDef(type, src, dst))) + goto error; + + if (VIR_EXPAND_N(def->fss, def->nfss, 1) < 0) + goto error; + def->fss[def->nfss - 1] = fsDef; + + return 0; + +error: + virDomainFSDefFree(fsDef); + return -1; +} + +static int +lxcSetRootfs(virDomainDefPtr def, + virPropertiesPtr properties) +{ + char *fssrc = NULL; + char *fsdst = NULL; + struct stat sb; + int type = VIR_DOMAIN_FS_TYPE_MOUNT; + + if (VIR_STRDUP(fssrc, virPropertiesLookup(properties, "lxc.rootfs")) < 0 || + VIR_STRDUP(fsdst, "/") < 0) + goto error; + + if (stat(fssrc, &sb) < 0) + goto error; + + if (S_ISBLK(sb.st_mode)) + type = VIR_DOMAIN_FS_TYPE_BLOCK; + + + if (lxcAddFSDef(def, type, fssrc, fsdst) < 0) + goto error; + + return 0; + +error: + VIR_FREE(fssrc); + VIR_FREE(fsdst); + return -1; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab ATTRIBUTE_UNUSED, @@ -246,6 +313,9 @@ lxcParseConfigString(const char *config, if (!vmdef->name && VIR_STRDUP(vmdef->name, "unnamed")) goto error; + if (lxcSetRootfs(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index a277751..621e699 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -13,5 +13,9 @@ <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> </devices> </domain> -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:51PM +0100, Cédric Bosdonnat wrote:
LXC rootfs can be either a directory or a block device or an image file. The first two types have been implemented, but the image file is still to be done since LXC auto-guesses the file format at mount time and the LXC driver doesn't support the 'auto' format. --- src/lxc/lxc_native.c | 70 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 74 insertions(+)
+static int +lxcSetRootfs(virDomainDefPtr def, + virPropertiesPtr properties) +{ + char *fssrc = NULL; + char *fsdst = NULL; + struct stat sb; + int type = VIR_DOMAIN_FS_TYPE_MOUNT; + + if (VIR_STRDUP(fssrc, virPropertiesLookup(properties, "lxc.rootfs")) < 0 || + VIR_STRDUP(fsdst, "/") < 0) + goto error; + + if (stat(fssrc, &sb) < 0) + goto error; + + if (S_ISBLK(sb.st_mode)) + type = VIR_DOMAIN_FS_TYPE_BLOCK;
I don't think we can assume that we can access the files listed in the config. The user might be just asking us to convert the file format, without the files being uploaded yet. So I think we must remove the 'stat' call, and instead do a "best effort" check of STRPREFIX(fssrc, "/dev") instead Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Tmpfs default usage is computed based on the host physical memory. To test this more easily, the value is computed outside the parse method. --- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_native.c | 295 ++++++++++++++++++++++++++- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 9 + 4 files changed, 302 insertions(+), 6 deletions(-) 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 2cd9143..9e2e870 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -21,11 +21,14 @@ */ #include <config.h> +#include <stdio.h> #include <sys/stat.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" @@ -206,7 +209,11 @@ lxcParseProperties(const char *properties) } static virDomainFSDefPtr -lxcCreateFSDef(int type, char *src, char* dst) +lxcCreateFSDef(int type, + char *src, + char* dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr def; @@ -217,16 +224,181 @@ 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 (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 lxcFstabPtr +lxcParseFstabString(const char *fstabString) +{ + lxcFstabPtr fstab = NULL; + char **lines; + size_t i; + lxcFstabPtr line = NULL; + + lines = virStringSplit(fstabString, "\n", 0); + + for (i = 0; lines[i]; i++) { + if (!(line = lxcParseFstabLine(lines[i]))) + continue; + line->next = fstab; + fstab = line; + } + + virStringFreeList(lines); + + return fstab; +} + +static lxcFstabPtr +lxcParseFstabFile(const char *path) +{ + lxcFstabPtr fstab = NULL; + FILE *fp = fopen(path, "r"); + char *tmp; + int tmplen = 0; + lxcFstabPtr line = NULL; + + if (!fp) { + char errbuf[1024]; + VIR_ERROR(_("Failed to open file %s: %s"), path, + virStrerror(errno, errbuf, sizeof(errbuf))); + goto cleanup; + } + + while (fgets(tmp, tmplen, fp) != NULL) { + if (tmplen == 0 || !(line = lxcParseFstabLine(tmp))) + continue; + line->next = fstab; + fstab = line; + } + + if (ferror(fp)) { + char errbuf[1024]; + VIR_ERROR(_("Failed to read file %s: %s"), path, + virStrerror(errno, errbuf, sizeof(errbuf))); + } + +cleanup: + VIR_FORCE_FCLOSE(fp); + + return fstab; +} + 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) @@ -260,7 +432,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; @@ -271,13 +443,90 @@ error: return -1; } +static unsigned long long +lxcConvertSize(const char *size, unsigned long memory) +{ + unsigned long long value = 0; + char *unit = NULL; + + /* Split the string into value and unit */ + if (virStrToLong_ull(size, &unit, 10, &value) < 0) + return 0; + + if (STREQ(unit, "%")) { + value = value * memory * 1024 / 100; + + } else if (virScaleInteger(&value, unit, 1, ULLONG_MAX) < 0) + return 0; + + return value; +} + +static int +lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab, unsigned long memory) +{ + 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="))) { + usage = lxcConvertSize(sizeStr, memory); + break; + } + } + /* Default tmpfs size is 50%, cf kernel doc */ + if (!sizeStr) + usage = lxcConvertSize("50%", memory); + } 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; +} + virDomainDefPtr lxcParseConfigString(const char *config, - const char *fstab ATTRIBUTE_UNUSED, + const char *fstab, unsigned long memory) { virDomainDefPtr vmdef = NULL; virPropertiesPtr properties = NULL; + lxcFstabPtr fstabEntries = NULL; + char *mountLine = NULL; + lxcFstabPtr fstabIter = NULL; if (!(properties = lxcParseProperties(config))) return NULL; @@ -290,6 +539,7 @@ lxcParseConfigString(const char *config, _("failed to generate uuid")); goto error; } + vmdef->id = -1; vmdef->mem.max_balloon = memory; @@ -302,6 +552,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; @@ -316,6 +568,38 @@ lxcParseConfigString(const char *config, if (lxcSetRootfs(vmdef, properties) < 0) goto error; + /* Look for fstab */ + if (!fstab) { + char *fstabPath = NULL; + if (VIR_STRDUP(fstabPath, virPropertiesLookup(properties, "lxc.mount")) < 0) + goto error; + + fstabEntries = lxcParseFstabFile(fstabPath); + VIR_FREE(fstabPath); + } else { + fstabEntries = lxcParseFstabString(fstab); + } + + /* Loop over lxc.mount.entry to add them to fstab */ + mountLine = virPropertiesLookup(properties, "lxc.mount.entry"); + while (mountLine) { + lxcFstabPtr fstabLine = lxcParseFstabLine(mountLine); + if (fstabLine) { + fstabLine->next = fstabEntries; + fstabEntries = fstabLine; + } + mountLine = virPropertiesLookup(properties, NULL); + } + + /* Loop over fstab entries to add filesystem devices for them */ + fstabIter = fstabEntries; + while (fstabIter) { + if (lxcAddFstabLine(vmdef, fstabIter, memory) < 0) + goto error; + + fstabIter = fstabIter->next; + } + goto cleanup; error: @@ -323,6 +607,7 @@ error: vmdef = NULL; cleanup: + lxcFstabFree(fstabEntries); virPropertiesFree(properties); return vmdef; diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index 621e699..8f2d442 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='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> </devices> </domain> -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:52PM +0100, Cédric Bosdonnat wrote:
@@ -316,6 +568,38 @@ lxcParseConfigString(const char *config, if (lxcSetRootfs(vmdef, properties) < 0) goto error;
+ /* Look for fstab */ + if (!fstab) { + char *fstabPath = NULL; + if (VIR_STRDUP(fstabPath, virPropertiesLookup(properties, "lxc.mount")) < 0) + goto error; + + fstabEntries = lxcParseFstabFile(fstabPath); + VIR_FREE(fstabPath);
I don't think this is going to fly for a couple of reasons. We can't assume that the dir/file/block device referenced in the config exists on the host we're doing the conversion on. If it is a block device or a plain file, then you can't access the /etc/fstab inside it either - you'd have to mount the filesystem first, which I don't think we want todo for this code. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Jan 14, 2014 at 02:49:52PM +0100, Cédric Bosdonnat wrote:
Tmpfs default usage is computed based on the host physical memory. To test this more easily, the value is computed outside the parse method. --- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_native.c | 295 ++++++++++++++++++++++++++- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 9 + 4 files changed, 302 insertions(+), 6 deletions(-)
+static unsigned long long +lxcConvertSize(const char *size, unsigned long memory) +{ + unsigned long long value = 0; + char *unit = NULL; + + /* Split the string into value and unit */ + if (virStrToLong_ull(size, &unit, 10, &value) < 0) + return 0; + + if (STREQ(unit, "%")) { + value = value * memory * 1024 / 100; + + } else if (virScaleInteger(&value, unit, 1, ULLONG_MAX) < 0) + return 0; + + return value; +}
This needs to virReportError in error cases. I'd probably suggest that the return value be an output parameter instead so we can return '-1' in an error case. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

If no network configuration is provided, LXC only provides the loopback interface. To match this, we need to use the privnet feature. --- src/lxc/lxc_native.c | 43 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 33 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 82 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 9e2e870..6b62a5b 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -517,6 +517,45 @@ error: return -1; } +static int +lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) +{ + virPropertyEntryPtr property = NULL; + char *type = NULL; + bool nonetwork = true; + + if (properties) { + for (property = properties->elements; + property; + property = property->next) { + if (STREQ(property->key, "lxc.network.type")) { + if ((type != NULL) && STRNEQ(type, "empty") && + STRNEQ(type, "")) { + nonetwork = false; + } + + /* Start a new network interface config */ + type = NULL; + + /* Keep the new value */ + type = property->value; + } + } + } + + if ((type != NULL) && STRNEQ(type, "empty") && + STRNEQ(type, "")) { + nonetwork = false; + } + + if (nonetwork) { + /* When no network type is provided LXC only adds loopback */ + def->features[VIR_DOMAIN_FEATURE_PRIVNET] = VIR_DOMAIN_FEATURE_STATE_ON; + } + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -600,6 +639,10 @@ lxcParseConfigString(const char *config, fstabIter = fstabIter->next; } + /* Network configuration */ + if (lxcConvertNetworkSettings(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config new file mode 100644 index 0000000..2da2a8f --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config @@ -0,0 +1,5 @@ +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.mount = /var/lib/lxc/migrate_test/fstab diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml new file mode 100644 index 0000000..d8bc318 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml @@ -0,0 +1,33 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 6f0f97e..34ddb67 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -107,6 +107,7 @@ mymain(void) ret = EXIT_FAILURE DO_TEST("simple"); + DO_TEST("nonetwork"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:53PM +0100, Cédric Bosdonnat wrote:
If no network configuration is provided, LXC only provides the loopback interface. To match this, we need to use the privnet feature. --- src/lxc/lxc_native.c | 43 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 33 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 82 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 9e2e870..6b62a5b 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -517,6 +517,45 @@ error: return -1; }
+static int +lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) +{ + virPropertyEntryPtr property = NULL; + char *type = NULL; + bool nonetwork = true; + + if (properties) { + for (property = properties->elements; + property; + property = property->next) { + if (STREQ(property->key, "lxc.network.type")) { + if ((type != NULL) && STRNEQ(type, "empty") && + STRNEQ(type, "")) { + nonetwork = false; + } + + /* Start a new network interface config */ + type = NULL; + + /* Keep the new value */ + type = property->value; + } + } + } + + if ((type != NULL) && STRNEQ(type, "empty") && + STRNEQ(type, "")) { + nonetwork = false; + }
IIUC, they use "lxc.network.type = none" to request sharing of the network namespace, rather than 'empty' Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Hi Dan, On Fri, 2014-01-24 at 13:34 +0000, Daniel P. Berrange wrote:
IIUC, they use "lxc.network.type = none" to request sharing of the network namespace, rather than 'empty'
Hum, the two values are existing, I'll need to implement 'none' too. That value arrived in mid-december with commit 26b797f3d29a4588c79d6b5ff77898d779b643f0: I didn't spot it when writing that code. -- Cedric

Some of the LXC configuration properties aren't migrated since they would only cause problems in libvirt-lxc: lxc.network.ipv[46]: LXC driver doesn't setup IP address of guests lxc.network.name --- src/lxc/lxc_native.c | 98 ++++++++++++++++++++++++++-- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 6b62a5b..a9ef453 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -517,35 +517,119 @@ error: return -1; } +static virDomainNetDefPtr +lxcCreateNetDef(const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + if (VIR_ALLOC(net) < 0) + goto error; + + if (flag) { + if (STREQ(flag, "up")) + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + else + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + } + + if (STREQ(type, "veth")) { + virMacAddr macAddr; + + if (!link) + goto error; + + net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + + if (VIR_STRDUP(net->data.bridge.brname, link) < 0) + goto error; + + if (mac && virMacAddrParse(mac, &macAddr) == 0) + net->mac = macAddr; + + } + + return net; + +error: + virDomainNetDefFree(net); + return NULL; +} + +static int +lxcAddNetworkDefinition(virDomainDefPtr def, + const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "")) + return 0; + + if (!(net = lxcCreateNetDef(type, link, mac, flag))) + goto error; + + if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) + goto error; + def->nets[def->nnets - 1] = net; + + return 1; + +error: + virDomainNetDefFree(net); + return -1; +} + static int lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) { virPropertyEntryPtr property = NULL; char *type = NULL; + char *link = NULL; + char *mac = NULL; + char *flag = NULL; bool nonetwork = true; + int status; if (properties) { for (property = properties->elements; property; property = property->next) { if (STREQ(property->key, "lxc.network.type")) { - if ((type != NULL) && STRNEQ(type, "empty") && - STRNEQ(type, "")) { + /* Store the previous NIC */ + status = lxcAddNetworkDefinition(def, type, link, mac, flag); + if (status < 0) + return -1; + else if (status > 0) nonetwork = false; - } /* Start a new network interface config */ type = NULL; + link = NULL; + mac = NULL; + flag = NULL; /* Keep the new value */ type = property->value; } + else if (STREQ(property->key, "lxc.network.link")) + link = property->value; + else if (STREQ(property->key, "lxc.network.hwaddr")) + mac = property->value; + else if (STREQ(property->key, "lxc.network.flags")) + flag = property->value; } - } - if ((type != NULL) && STRNEQ(type, "empty") && - STRNEQ(type, "")) { - nonetwork = false; + /* Add the last network definition found */ + status = lxcAddNetworkDefinition(def, type, link, mac, flag); + if (status < 0) + return -1; + else if (status > 0) + nonetwork = false; } if (nonetwork) { diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index 8f2d442..de249ea 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -26,5 +26,10 @@ <source usage='2017885' units='KiB'/> <target dir='/run'/> </filesystem> + <interface type='bridge'> + <mac address='02:00:15:8f:05:c1'/> + <source bridge='virbr0'/> + <link state='up'/> + </interface> </devices> </domain> -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:54PM +0100, Cédric Bosdonnat wrote:
Some of the LXC configuration properties aren't migrated since they would only cause problems in libvirt-lxc: lxc.network.ipv[46]: LXC driver doesn't setup IP address of guests
That doesn't make sense in a machine virt world, but has been requested a few times in the context of LXC and before that with OpenVZ. I guess we need a bug filed to request that we support this. Currently I have to workaround it with libvirt-sandbox's LXC support too
lxc.network.name
What is this config param for ? Is that the name of the guest visible NIC ? Currently we hardcode it ethNNN, assigning the NNN value incrementally. Guess that'd be another RFE bug.
--- src/lxc/lxc_native.c | 98 ++++++++++++++++++++++++++-- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 6b62a5b..a9ef453 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -517,35 +517,119 @@ error: return -1; }
+static virDomainNetDefPtr +lxcCreateNetDef(const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + if (VIR_ALLOC(net) < 0) + goto error; + + if (flag) { + if (STREQ(flag, "up")) + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + else + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + }
Hmm, the LXC driver doesn't honour the 'linkstate' config parameter currently, so we need a bug about that filed, or feel free to do a patch for that.
+ + if (STREQ(type, "veth")) { + virMacAddr macAddr; + + if (!link) + goto error; + + net->type = VIR_DOMAIN_NET_TYPE_BRIDGE; + + if (VIR_STRDUP(net->data.bridge.brname, link) < 0) + goto error; + + if (mac && virMacAddrParse(mac, &macAddr) == 0) + net->mac = macAddr; + + } + + return net; + +error: + virDomainNetDefFree(net); + return NULL; +} +
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Hi Dan, On Fri, 2014-01-24 at 13:39 +0000, Daniel P. Berrange wrote:
On Tue, Jan 14, 2014 at 02:49:54PM +0100, Cédric Bosdonnat wrote:
Some of the LXC configuration properties aren't migrated since they would only cause problems in libvirt-lxc: lxc.network.ipv[46]: LXC driver doesn't setup IP address of guests
That doesn't make sense in a machine virt world, but has been requested a few times in the context of LXC and before that with OpenVZ. I guess we need a bug filed to request that we support this. Currently I have to workaround it with libvirt-sandbox's LXC support too
lxc.network.name
What is this config param for ? Is that the name of the guest visible NIC ? Currently we hardcode it ethNNN, assigning the NNN value incrementally. Guess that'd be another RFE bug.
Then I'll file those bugs.
--- src/lxc/lxc_native.c | 98 ++++++++++++++++++++++++++-- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 6b62a5b..a9ef453 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -517,35 +517,119 @@ error: return -1; }
+static virDomainNetDefPtr +lxcCreateNetDef(const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + if (VIR_ALLOC(net) < 0) + goto error; + + if (flag) { + if (STREQ(flag, "up")) + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + else + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + }
Hmm, the LXC driver doesn't honour the 'linkstate' config parameter currently, so we need a bug about that filed, or feel free to do a patch for that.
I'ld prefer a patch, but doesn't that make sense at all if LXC driver doesn't assign IP addresses? -- Cedric

On Fri, Jan 24, 2014 at 03:19:31PM +0100, Cedric Bosdonnat wrote:
Hi Dan,
On Fri, 2014-01-24 at 13:39 +0000, Daniel P. Berrange wrote:
On Tue, Jan 14, 2014 at 02:49:54PM +0100, Cédric Bosdonnat wrote:
Some of the LXC configuration properties aren't migrated since they would only cause problems in libvirt-lxc: lxc.network.ipv[46]: LXC driver doesn't setup IP address of guests
That doesn't make sense in a machine virt world, but has been requested a few times in the context of LXC and before that with OpenVZ. I guess we need a bug filed to request that we support this. Currently I have to workaround it with libvirt-sandbox's LXC support too
lxc.network.name
What is this config param for ? Is that the name of the guest visible NIC ? Currently we hardcode it ethNNN, assigning the NNN value incrementally. Guess that'd be another RFE bug.
Then I'll file those bugs.
--- src/lxc/lxc_native.c | 98 ++++++++++++++++++++++++++-- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 6b62a5b..a9ef453 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -517,35 +517,119 @@ error: return -1; }
+static virDomainNetDefPtr +lxcCreateNetDef(const char *type, + const char *link, + const char *mac, + const char *flag) +{ + virDomainNetDefPtr net = NULL; + + if (VIR_ALLOC(net) < 0) + goto error; + + if (flag) { + if (STREQ(flag, "up")) + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + else + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + }
Hmm, the LXC driver doesn't honour the 'linkstate' config parameter currently, so we need a bug about that filed, or feel free to do a patch for that.
I'ld prefer a patch, but doesn't that make sense at all if LXC driver doesn't assign IP addresses?
Hmm, if the link is up, then you would at least have IPv6 automatic configuration working. so it would be useful even if we don't do static IP configs. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 43 +++++++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 8 ++++ tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 35 ++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index a9ef453..3667d04 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -558,6 +558,26 @@ error: return NULL; } +static virDomainHostdevDefPtr +lxcCreateHostdevDef(int mode, int type, const char *data) +{ + virDomainHostdevDefPtr hostdev = virDomainHostdevDefAlloc(); + + if (!hostdev) + return NULL; + + hostdev->mode = mode; + hostdev->source.caps.type = type; + + if (type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET && + VIR_STRDUP(hostdev->source.caps.u.net.iface, data) < 0) { + virDomainHostdevDefFree(hostdev); + hostdev = NULL; + } + + return hostdev; +} + static int lxcAddNetworkDefinition(virDomainDefPtr def, const char *type, @@ -566,21 +586,34 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *flag) { virDomainNetDefPtr net = NULL; + virDomainHostdevDefPtr hostdev = NULL; if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "")) return 0; - if (!(net = lxcCreateNetDef(type, link, mac, flag))) - goto error; + if (type != NULL && STREQ(type, "phys")) { + if (!(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES, + VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET, + link))) + goto error; - if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) - goto error; - def->nets[def->nnets - 1] = net; + if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0) + goto error; + def->hostdevs[def->nhostdevs - 1] = hostdev; + } else { + if (!(net = lxcCreateNetDef(type, link, mac, flag))) + goto error; + + if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) + goto error; + def->nets[def->nnets - 1] = net; + } return 1; error: virDomainNetDefFree(net); + virDomainHostdevDefFree(hostdev); return -1; } diff --git a/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config new file mode 100644 index 0000000..5f113e4 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config @@ -0,0 +1,8 @@ +lxc.network.type = phys +lxc.network.link = eth0 + +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.mount = /var/lib/lxc/migrate_test/fstab diff --git a/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml new file mode 100644 index 0000000..98edfef --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml @@ -0,0 +1,35 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + <hostdev mode='capabilities' type='net'> + <source> + <interface>eth0</interface> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 34ddb67..fe2e3bc 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST("simple"); DO_TEST("nonetwork"); + DO_TEST("physnetwork"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:55PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 43 +++++++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 8 ++++ tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 35 ++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml
ACK, makes sense. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 41 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 6 ++++ 2 files changed, 47 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 3667d04..6ea4998 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -673,6 +673,43 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) return 0; } +static int +lxcCreateConsoles(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *tty; + int nbttys = 0; + virDomainChrDefPtr console; + size_t i; + + if (!(tty = virPropertiesLookup(properties, "lxc.tty"))) + return 0; + + if (virStrToLong_i(tty, NULL, 10, &nbttys) < 0) + return -1; + + if (VIR_ALLOC_N(def->consoles, nbttys) < 0) + return -1; + + def->nconsoles = nbttys; + for (i = 0; i < nbttys; i++) { + if (!(console = virDomainChrDefNew())) + goto error; + + console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; + console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC; + console->target.port = i; + console->source.type = VIR_DOMAIN_CHR_TYPE_PTY; + + def->consoles[i] = console; + } + + return 0; + +error: + virDomainChrDefFree(console); + return -1; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -760,6 +797,10 @@ lxcParseConfigString(const char *config, if (lxcConvertNetworkSettings(vmdef, properties) < 0) goto error; + /* Consoles */ + if (lxcCreateConsoles(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index de249ea..763ba1b 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -31,5 +31,11 @@ <source bridge='virbr0'/> <link state='up'/> </interface> + <console type='pty'> + <target type='lxc' port='0'/> + </console> + <console type='pty'> + <target type='lxc' port='1'/> + </console> </devices> </domain> -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:56PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 41 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 6 ++++ 2 files changed, 47 insertions(+)
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 3667d04..6ea4998 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -673,6 +673,43 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) return 0; }
+static int +lxcCreateConsoles(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *tty; + int nbttys = 0; + virDomainChrDefPtr console; + size_t i; + + if (!(tty = virPropertiesLookup(properties, "lxc.tty"))) + return 0; + + if (virStrToLong_i(tty, NULL, 10, &nbttys) < 0) + return -1;
You need to virReportError when this fails to parse.
+ + if (VIR_ALLOC_N(def->consoles, nbttys) < 0) + return -1; + + def->nconsoles = nbttys; + for (i = 0; i < nbttys; i++) { + if (!(console = virDomainChrDefNew())) + goto error; + + console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; + console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC; + console->target.port = i; + console->source.type = VIR_DOMAIN_CHR_TYPE_PTY; + + def->consoles[i] = console; + } + + return 0; + +error: + virDomainChrDefFree(console); + return -1; +} +
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 38 +++++++++++++++++----- .../lxcconf2xml-macvlannetwork.config | 14 ++++++++ .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 30 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 6ea4998..a99bc1c 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -521,9 +521,11 @@ static virDomainNetDefPtr lxcCreateNetDef(const char *type, const char *link, const char *mac, - const char *flag) + const char *flag, + const char *macvlanmode) { virDomainNetDefPtr net = NULL; + virMacAddr macAddr; if (VIR_ALLOC(net) < 0) goto error; @@ -535,9 +537,11 @@ lxcCreateNetDef(const char *type, net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; } - if (STREQ(type, "veth")) { - virMacAddr macAddr; + if (mac && virMacAddrParse(mac, &macAddr) == 0) + net->mac = macAddr; + + if (STREQ(type, "veth")) { if (!link) goto error; @@ -546,9 +550,18 @@ lxcCreateNetDef(const char *type, if (VIR_STRDUP(net->data.bridge.brname, link) < 0) goto error; - if (mac && virMacAddrParse(mac, &macAddr) == 0) - net->mac = macAddr; + } else if (STREQ(type, "macvlan")) { + net->type = VIR_DOMAIN_NET_TYPE_DIRECT; + + if (VIR_STRDUP(net->data.direct.linkdev, link) < 0) + goto error; + if (!macvlanmode || STREQ(macvlanmode, "private")) + net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE; + else if (STREQ(macvlanmode, "vepa")) + net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA; + else if (STREQ(macvlanmode, "bridget")) + net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE; } return net; @@ -583,7 +596,8 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *type, const char *link, const char *mac, - const char *flag) + const char *flag, + const char *macvlanmode) { virDomainNetDefPtr net = NULL; virDomainHostdevDefPtr hostdev = NULL; @@ -601,7 +615,7 @@ lxcAddNetworkDefinition(virDomainDefPtr def, goto error; def->hostdevs[def->nhostdevs - 1] = hostdev; } else { - if (!(net = lxcCreateNetDef(type, link, mac, flag))) + if (!(net = lxcCreateNetDef(type, link, mac, flag, macvlanmode))) goto error; if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) @@ -625,6 +639,7 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) char *link = NULL; char *mac = NULL; char *flag = NULL; + char *macvlanmode = NULL; bool nonetwork = true; int status; @@ -634,7 +649,8 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) property = property->next) { if (STREQ(property->key, "lxc.network.type")) { /* Store the previous NIC */ - status = lxcAddNetworkDefinition(def, type, link, mac, flag); + status = lxcAddNetworkDefinition(def, type, link, mac, flag, + macvlanmode); if (status < 0) return -1; else if (status > 0) @@ -645,6 +661,7 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) link = NULL; mac = NULL; flag = NULL; + macvlanmode = NULL; /* Keep the new value */ type = property->value; @@ -655,10 +672,13 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) mac = property->value; else if (STREQ(property->key, "lxc.network.flags")) flag = property->value; + else if (STREQ(property->key, "lxc.network.macvlan.mode")) + macvlanmode = property->value; } /* Add the last network definition found */ - status = lxcAddNetworkDefinition(def, type, link, mac, flag); + status = lxcAddNetworkDefinition(def, type, link, mac, flag, + macvlanmode); if (status < 0) return -1; else if (status > 0) diff --git a/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config new file mode 100644 index 0000000..3fa2c78 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config @@ -0,0 +1,14 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = macvlan +lxc.network.flags = up +lxc.network.link = eth0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.macvlan.mode = vepa + +#remove next line if host DNS configuration should not be available to container +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.mount = /var/lib/lxc/migrate_test/fstab diff --git a/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml new file mode 100644 index 0000000..6e52f75 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml @@ -0,0 +1,30 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + <interface type='direct'> + <mac address='02:00:15:8f:05:c1'/> + <source dev='eth0' mode='vepa'/> + <link state='up'/> + </interface> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index fe2e3bc..8d23a11 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -109,6 +109,7 @@ mymain(void) DO_TEST("simple"); DO_TEST("nonetwork"); DO_TEST("physnetwork"); + DO_TEST("macvlannetwork"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:57PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 38 +++++++++++++++++----- .../lxcconf2xml-macvlannetwork.config | 14 ++++++++ .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 30 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 6ea4998..a99bc1c 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -521,9 +521,11 @@ static virDomainNetDefPtr lxcCreateNetDef(const char *type, const char *link, const char *mac, - const char *flag) + const char *flag, + const char *macvlanmode) { virDomainNetDefPtr net = NULL; + virMacAddr macAddr;
if (VIR_ALLOC(net) < 0) goto error; @@ -535,9 +537,11 @@ lxcCreateNetDef(const char *type, net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; }
- if (STREQ(type, "veth")) { - virMacAddr macAddr;
+ if (mac && virMacAddrParse(mac, &macAddr) == 0) + net->mac = macAddr; + + if (STREQ(type, "veth")) { if (!link) goto error;
@@ -546,9 +550,18 @@ lxcCreateNetDef(const char *type, if (VIR_STRDUP(net->data.bridge.brname, link) < 0) goto error;
- if (mac && virMacAddrParse(mac, &macAddr) == 0) - net->mac = macAddr; + } else if (STREQ(type, "macvlan")) { + net->type = VIR_DOMAIN_NET_TYPE_DIRECT; + + if (VIR_STRDUP(net->data.direct.linkdev, link) < 0) + goto error;
+ if (!macvlanmode || STREQ(macvlanmode, "private")) + net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE; + else if (STREQ(macvlanmode, "vepa")) + net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA; + else if (STREQ(macvlanmode, "bridget"))
Is that really meant to be 'bridget' is is that a typo ?
+ net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
We should likely have a 'else' clause which reports an error
@@ -655,10 +672,13 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) mac = property->value; else if (STREQ(property->key, "lxc.network.flags")) flag = property->value; + else if (STREQ(property->key, "lxc.network.macvlan.mode")) + macvlanmode = property->value;
Perhaps we want to have a 'VIR_WARN' statement here. Reporting an error is a bit harsh, since we want to make best effort to report something sensible, so a VIR_WARN at least lets us know we've work todo
}
/* Add the last network definition found */ - status = lxcAddNetworkDefinition(def, type, link, mac, flag); + status = lxcAddNetworkDefinition(def, type, link, mac, flag, + macvlanmode); if (status < 0) return -1; else if (status > 0)
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 41 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 6 ++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 32 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 80 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index a99bc1c..7cb5125 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -730,6 +730,43 @@ error: return -1; } +static int +lxcCreateIdmap(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value = NULL; + virDomainIdMapEntryPtr idmap = NULL; + char type; + unsigned long start, target, count; + + value = virPropertiesLookup(properties, "lxc.id_map"); + while (value) { + if (sscanf(value, "%c %lu %lu %lu", &type, &target, &start, &count) != 4) + return -1; + + if (VIR_ALLOC(idmap) < 0) + return -1; + + if (type == 'u') { + if (VIR_EXPAND_N(def->idmap.uidmap, def->idmap.nuidmap, 1) < 0) + return -1; + idmap = &def->idmap.uidmap[def->idmap.nuidmap - 1]; + } else if (type == 'g') { + if (VIR_EXPAND_N(def->idmap.gidmap, def->idmap.ngidmap, 1) < 0) + return -1; + idmap = &def->idmap.gidmap[def->idmap.ngidmap - 1]; + } else + return -1; + + idmap->start = start; + idmap->target = target; + idmap->count = count; + + value = virPropertiesLookup(properties, NULL); + } + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -821,6 +858,10 @@ lxcParseConfigString(const char *config, if (lxcCreateConsoles(vmdef, properties) < 0) goto error; + /* lxc.id_map */ + if (lxcCreateIdmap(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-idmap.config b/tests/lxcconf2xmldata/lxcconf2xml-idmap.config new file mode 100644 index 0000000..1eedbe8 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-idmap.config @@ -0,0 +1,6 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.mount = /var/lib/lxc/migrate_test/fstab + +lxc.id_map = u 10000 0 2000 +lxc.id_map = g 10000 0 1000 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml b/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml new file mode 100644 index 0000000..6de99af --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml @@ -0,0 +1,32 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <idmap> + <uid start='0' target='10000' count='2000'/> + <gid start='0' target='10000' count='1000'/> + </idmap> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 8d23a11..6793c29 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -110,6 +110,7 @@ mymain(void) DO_TEST("nonetwork"); DO_TEST("physnetwork"); DO_TEST("macvlannetwork"); + DO_TEST("idmap"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:58PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 41 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 6 ++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 32 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 80 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index a99bc1c..7cb5125 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -730,6 +730,43 @@ error: return -1; }
+static int +lxcCreateIdmap(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value = NULL; + virDomainIdMapEntryPtr idmap = NULL; + char type; + unsigned long start, target, count; + + value = virPropertiesLookup(properties, "lxc.id_map"); + while (value) { + if (sscanf(value, "%c %lu %lu %lu", &type, &target, &start, &count) != 4) + return -1;
Need a virReportError here.
+ + if (VIR_ALLOC(idmap) < 0) + return -1; + + if (type == 'u') { + if (VIR_EXPAND_N(def->idmap.uidmap, def->idmap.nuidmap, 1) < 0) + return -1; + idmap = &def->idmap.uidmap[def->idmap.nuidmap - 1]; + } else if (type == 'g') { + if (VIR_EXPAND_N(def->idmap.gidmap, def->idmap.ngidmap, 1) < 0) + return -1; + idmap = &def->idmap.gidmap[def->idmap.ngidmap - 1]; + } else + return -1; + + idmap->start = start; + idmap->target = target; + idmap->count = count; + + value = virPropertiesLookup(properties, NULL); + } + + return 0; +}
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 26 ++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 12 ++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 38 ++++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 7cb5125..582924e 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -767,6 +767,29 @@ lxcCreateIdmap(virDomainDefPtr def, virPropertiesPtr properties) return 0; } +static void +lxcSetMemTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value = NULL; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.memory.limit_in_bytes")) && STRNEQ(value, "-1")) { + unsigned long long size = lxcConvertSize(value, 0) / 1024; + def->mem.max_balloon = size; + def->mem.hard_limit = size; + } + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.memory.soft_limit_in_bytes")) && + STRNEQ(value, "-1")) + def->mem.soft_limit = lxcConvertSize(value, 0) / 1024; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.memory.memsw.limit_in_bytes")) && + STRNEQ(value, "-1")) + def->mem.swap_hard_limit = lxcConvertSize(value, 0) / 1024; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -862,6 +885,9 @@ lxcParseConfigString(const char *config, if (lxcCreateIdmap(vmdef, properties) < 0) goto error; + /* lxc.cgroup.memory.* */ + lxcSetMemTune(vmdef, properties); + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-memtune.config b/tests/lxcconf2xmldata/lxcconf2xml-memtune.config new file mode 100644 index 0000000..ef01e23 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-memtune.config @@ -0,0 +1,12 @@ +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.mount = /var/lib/lxc/migrate_test/fstab + +# 1GiB +lxc.cgroup.memory.limit_in_bytes = 1073741824 +# 128MiB +lxc.cgroup.memory.soft_limit_in_bytes = 134217728 +# 2GiB +lxc.cgroup.memory.memsw.limit_in_bytes = 2147483648 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml b/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml new file mode 100644 index 0000000..4e4698e --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml @@ -0,0 +1,38 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>0</currentMemory> + <memtune> + <hard_limit unit='KiB'>1048576</hard_limit> + <soft_limit unit='KiB'>131072</soft_limit> + <swap_hard_limit unit='KiB'>2097152</swap_hard_limit> + </memtune> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 6793c29..bf5b06e 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -111,6 +111,7 @@ mymain(void) DO_TEST("physnetwork"); DO_TEST("macvlannetwork"); DO_TEST("idmap"); + DO_TEST("memtune"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:49:59PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 26 ++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 12 ++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 38 ++++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 7cb5125..582924e 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -767,6 +767,29 @@ lxcCreateIdmap(virDomainDefPtr def, virPropertiesPtr properties) return 0; }
+static void +lxcSetMemTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value = NULL; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.memory.limit_in_bytes")) && STRNEQ(value, "-1")) { + unsigned long long size = lxcConvertSize(value, 0) / 1024; + def->mem.max_balloon = size; + def->mem.hard_limit = size; + } + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.memory.soft_limit_in_bytes")) && + STRNEQ(value, "-1")) + def->mem.soft_limit = lxcConvertSize(value, 0) / 1024; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.memory.memsw.limit_in_bytes")) && + STRNEQ(value, "-1")) + def->mem.swap_hard_limit = lxcConvertSize(value, 0) / 1024; +}
These calls to lxcConvertSize need to deal with error propagation to the caller Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 26 ++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 9 ++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 38 ++++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 74 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 582924e..80b7e74 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -790,6 +790,28 @@ lxcSetMemTune(virDomainDefPtr def, virPropertiesPtr properties) def->mem.swap_hard_limit = lxcConvertSize(value, 0) / 1024; } +static int +lxcSetCpuTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value; + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.cpu.shares")) && + virStrToLong_ul(value, NULL, 10, &def->cputune.shares) < 0) + return -1; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.cpu.cfs_quota_us")) && + virStrToLong_ll(value, NULL, 10, &def->cputune.quota) < 0) + return -1; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.cpu.cfs_period_us")) && + virStrToLong_ull(value, NULL, 10, &def->cputune.period) < 0) + return -1; + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -888,6 +910,10 @@ lxcParseConfigString(const char *config, /* lxc.cgroup.memory.* */ lxcSetMemTune(vmdef, properties); + /* lxc.cgroup.cpu.* */ + if (lxcSetCpuTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cputune.config b/tests/lxcconf2xmldata/lxcconf2xml-cputune.config new file mode 100644 index 0000000..3c1448e --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cputune.config @@ -0,0 +1,9 @@ +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.mount = /var/lib/lxc/migrate_test/fstab + +lxc.cgroup.cpu.shares = 1024 +lxc.cgroup.cpu.cfs_quota_us = -1 +lxc.cgroup.cpu.cfs_period_us = 500000 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml b/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml new file mode 100644 index 0000000..b35b3e3 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml @@ -0,0 +1,38 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <cputune> + <shares>1024</shares> + <period>500000</period> + <quota>-1</quota> + </cputune> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index bf5b06e..096a050 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -112,6 +112,7 @@ mymain(void) DO_TEST("macvlannetwork"); DO_TEST("idmap"); DO_TEST("memtune"); + DO_TEST("cputune"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:50:00PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 26 ++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 9 ++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 38 ++++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 74 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 582924e..80b7e74 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -790,6 +790,28 @@ lxcSetMemTune(virDomainDefPtr def, virPropertiesPtr properties) def->mem.swap_hard_limit = lxcConvertSize(value, 0) / 1024; }
+static int +lxcSetCpuTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value; + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.cpu.shares")) && + virStrToLong_ul(value, NULL, 10, &def->cputune.shares) < 0) + return -1; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.cpu.cfs_quota_us")) && + virStrToLong_ll(value, NULL, 10, &def->cputune.quota) < 0) + return -1; + + if ((value = virPropertiesLookup(properties, + "lxc.cgroup.cpu.cfs_period_us")) && + virStrToLong_ull(value, NULL, 10, &def->cputune.period) < 0) + return -1; + + return 0; +}
Again error reporting when virStrToLong_ull fails Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 27 ++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 8 +++++ tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 36 ++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 72 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 80b7e74..635eb89 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -812,6 +812,29 @@ lxcSetCpuTune(virDomainDefPtr def, virPropertiesPtr properties) return 0; } +static int +lxcSetCpusetTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value; + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.cpuset.cpus"))) { + if (virBitmapParse(value, 0, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + + def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC; + } + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.cpuset.mems"))) { + def->numatune.memory.placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC; + def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT; + if (virBitmapParse(value, 0, &def->numatune.memory.nodemask, + VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + } + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -914,6 +937,10 @@ lxcParseConfigString(const char *config, if (lxcSetCpuTune(vmdef, properties) < 0) goto error; + /* lxc.cgroup.cpuset.* */ + if (lxcSetCpusetTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config new file mode 100644 index 0000000..0ece9fc --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config @@ -0,0 +1,8 @@ +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.mount = /var/lib/lxc/migrate_test/fstab + +lxc.cgroup.cpuset.cpus = 1,2,5-7 +lxc.cgroup.cpuset.mems = 1-4 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml new file mode 100644 index 0000000..d22a7fe --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml @@ -0,0 +1,36 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' cpuset='1-2,5-7' current='0'>1</vcpu> + <numatune> + <memory mode='strict' nodeset='1-4'/> + </numatune> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 096a050..da94db4 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -113,6 +113,7 @@ mymain(void) DO_TEST("idmap"); DO_TEST("memtune"); DO_TEST("cputune"); + DO_TEST("cpusettune"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:50:01PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 27 ++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 8 +++++ tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 36 ++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 72 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 80b7e74..635eb89 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -812,6 +812,29 @@ lxcSetCpuTune(virDomainDefPtr def, virPropertiesPtr properties) return 0; }
+static int +lxcSetCpusetTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value;
BTW this should be 'const' throughout this series
+ + if ((value = virPropertiesLookup(properties, "lxc.cgroup.cpuset.cpus"))) { + if (virBitmapParse(value, 0, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + + def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC; + } + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.cpuset.mems"))) { + def->numatune.memory.placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC; + def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT; + if (virBitmapParse(value, 0, &def->numatune.memory.nodemask, + VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + } + + return 0; +}
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 9 +++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 44 ++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 98 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 635eb89..75e05a5 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -835,6 +835,46 @@ lxcSetCpusetTune(virDomainDefPtr def, virPropertiesPtr properties) return 0; } +static int +lxcSetBlkioTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value; + char **parts; + virBlkioDevicePtr device = NULL; + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.blkio.weight")) && + virStrToLong_ui(value, NULL, 10, &def->blkio.weight) < 0) + return -1; + + value = virPropertiesLookup(properties, "lxc.cgroup.blkio.device_weight"); + while (value) { + if (!(parts = lxcStringSplit(value))) + return -1; + + if (!parts[0] || !parts[1]) + goto error; + + if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) + goto error; + device = &def->blkio.devices[def->blkio.ndevices - 1]; + + if (virAsprintf(&device->path, "/dev/block/%s", parts[0]) < 0) + goto error; + + if (virStrToLong_ui(parts[1], NULL, 10, &device->weight) < 0) + goto error; + + virStringFreeList(parts); + value = virPropertiesLookup(properties, NULL); + } + + return 0; + +error: + virStringFreeList(parts); + return -1; +} + virDomainDefPtr lxcParseConfigString(const char *config, const char *fstab, @@ -941,6 +981,10 @@ lxcParseConfigString(const char *config, if (lxcSetCpusetTune(vmdef, properties) < 0) goto error; + /* lxc.cgroup.blkio.* */ + if (lxcSetBlkioTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config new file mode 100644 index 0000000..704c737 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config @@ -0,0 +1,9 @@ +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.mount = /var/lib/lxc/migrate_test/fstab + +lxc.cgroup.blkio.weight = 500 +lxc.cgroup.blkio.device_weight = 8:16 1000 +lxc.cgroup.blkio.device_weight = 8:0 300 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml new file mode 100644 index 0000000..51d2881 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -0,0 +1,44 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <blkiotune> + <weight>500</weight> + <device> + <path>/dev/block/8:16</path> + <weight>1000</weight> + </device> + <device> + <path>/dev/block/8:0</path> + <weight>300</weight> + </device> + </blkiotune> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <features> + <privnet/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index da94db4..60fdb01 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -114,6 +114,7 @@ mymain(void) DO_TEST("memtune"); DO_TEST("cputune"); DO_TEST("cpusettune"); + DO_TEST("blkiotune"); return ret; } -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:50:02PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 9 +++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 44 ++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 98 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 635eb89..75e05a5 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -835,6 +835,46 @@ lxcSetCpusetTune(virDomainDefPtr def, virPropertiesPtr properties) return 0; }
+static int +lxcSetBlkioTune(virDomainDefPtr def, virPropertiesPtr properties) +{ + char *value; + char **parts; + virBlkioDevicePtr device = NULL; + + if ((value = virPropertiesLookup(properties, "lxc.cgroup.blkio.weight")) && + virStrToLong_ui(value, NULL, 10, &def->blkio.weight) < 0) + return -1; + + value = virPropertiesLookup(properties, "lxc.cgroup.blkio.device_weight"); + while (value) { + if (!(parts = lxcStringSplit(value))) + return -1; + + if (!parts[0] || !parts[1]) + goto error; + + if (VIR_EXPAND_N(def->blkio.devices, def->blkio.ndevices, 1) < 0) + goto error; + device = &def->blkio.devices[def->blkio.ndevices - 1]; + + if (virAsprintf(&device->path, "/dev/block/%s", parts[0]) < 0) + goto error; + + if (virStrToLong_ui(parts[1], NULL, 10, &device->weight) < 0) + goto error;
virReportError here Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 8 ++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 1 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 75e05a5..1c0f325 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -882,6 +882,7 @@ lxcParseConfigString(const char *config, { virDomainDefPtr vmdef = NULL; virPropertiesPtr properties = NULL; + char *arch = NULL; lxcFstabPtr fstabEntries = NULL; char *mountLine = NULL; lxcFstabPtr fstabIter = NULL; @@ -915,6 +916,13 @@ lxcParseConfigString(const char *config, if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error; + if ((arch = virPropertiesLookup(properties, "lxc.arch"))) { + if (STREQ(arch, "x86") || STREQ(arch, "i686")) + vmdef->os.arch = VIR_ARCH_I686; + else if (STREQ(arch, "x86_64") || STREQ(arch, "amd64")) + vmdef->os.arch = VIR_ARCH_X86_64; + } + if (VIR_STRDUP(vmdef->os.init, "/sbin/init") < 0) goto error; diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config index 12428bb..3553881 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.config +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -11,6 +11,7 @@ lxc.network.name = eth0 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.arch = x86 lxc.autodev=1 lxc.tty = 2 lxc.pts = 1024 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index 763ba1b..4027ea7 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -5,7 +5,7 @@ <currentMemory unit='KiB'>0</currentMemory> <vcpu placement='static' current='0'>1</vcpu> <os> - <type>exe</type> + <type arch='i686'>exe</type> <init>/sbin/init</init> </os> <clock offset='utc'/> -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:50:03PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 8 ++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 1 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 75e05a5..1c0f325 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -882,6 +882,7 @@ lxcParseConfigString(const char *config, { virDomainDefPtr vmdef = NULL; virPropertiesPtr properties = NULL; + char *arch = NULL; lxcFstabPtr fstabEntries = NULL; char *mountLine = NULL; lxcFstabPtr fstabIter = NULL; @@ -915,6 +916,13 @@ lxcParseConfigString(const char *config, if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error;
+ if ((arch = virPropertiesLookup(properties, "lxc.arch"))) { + if (STREQ(arch, "x86") || STREQ(arch, "i686")) + vmdef->os.arch = VIR_ARCH_I686; + else if (STREQ(arch, "x86_64") || STREQ(arch, "amd64")) + vmdef->os.arch = VIR_ARCH_X86_64; + }
How about calling virArchFromString() to handle the common case, and then only special-case the non-standard 'x86' and 'amd64' names Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/lxc/lxc_native.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 1c0f325..5ba6f94 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -471,6 +471,7 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab, unsigned long memory) bool readonly; int type = VIR_DOMAIN_FS_TYPE_MOUNT; unsigned long long usage = 0; + struct stat sb; if (fstab->dst[0] != '/') { if (virAsprintf(&dst, "/%s", fstab->dst) < 0) @@ -501,6 +502,10 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab, unsigned long memory) } else if (VIR_STRDUP(src, fstab->src) < 0) goto error; + /* Is it a block device that needs special favor? */ + if (stat(fstab->src, &sb) >= 0 && S_ISBLK(sb.st_mode)) + type = VIR_DOMAIN_FS_TYPE_BLOCK; + /* Do we have ro in options? */ readonly = virStringArrayHasString(options, "ro"); -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:50:04PM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 1c0f325..5ba6f94 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -471,6 +471,7 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab, unsigned long memory) bool readonly; int type = VIR_DOMAIN_FS_TYPE_MOUNT; unsigned long long usage = 0; + struct stat sb;
if (fstab->dst[0] != '/') { if (virAsprintf(&dst, "/%s", fstab->dst) < 0) @@ -501,6 +502,10 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab, unsigned long memory) } else if (VIR_STRDUP(src, fstab->src) < 0) goto error;
+ /* Is it a block device that needs special favor? */ + if (stat(fstab->src, &sb) >= 0 && S_ISBLK(sb.st_mode)) + type = VIR_DOMAIN_FS_TYPE_BLOCK;
Here we'll have to do the STRPREFIX(src, "/dev") approach again instead of stat() Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent. lxc.network.type = phys lxc.network.link = eth0.5 lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5 --- src/lxc/lxc_native.c | 23 ++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 13 ++++++++++ tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 30 ++++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 5ba6f94..68ab965 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -602,20 +602,31 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *link, const char *mac, const char *flag, - const char *macvlanmode) + const char *macvlanmode, + const char *vlanid) { virDomainNetDefPtr net = NULL; virDomainHostdevDefPtr hostdev = NULL; + bool isPhys, isVlan = false; if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "")) return 0; - if (type != NULL && STREQ(type, "phys")) { + isPhys = STREQ(type, "phys"); + isVlan = STREQ(type, "vlan"); + if (type != NULL && (isPhys || isVlan)) { if (!(hostdev = lxcCreateHostdevDef(VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET, link))) goto error; + /* This still requires the user to manually setup the vlan interface + * on the host */ + if (isVlan && !(link && vlanid && + virAsprintf(&hostdev->source.caps.u.net.iface, + "%s.%s", link, vlanid) >= 0)) + goto error; + if (VIR_EXPAND_N(def->hostdevs, def->nhostdevs, 1) < 0) goto error; def->hostdevs[def->nhostdevs - 1] = hostdev; @@ -645,6 +656,7 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) char *mac = NULL; char *flag = NULL; char *macvlanmode = NULL; + char *vlanid = NULL; bool nonetwork = true; int status; @@ -655,7 +667,7 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) if (STREQ(property->key, "lxc.network.type")) { /* Store the previous NIC */ status = lxcAddNetworkDefinition(def, type, link, mac, flag, - macvlanmode); + macvlanmode, vlanid); if (status < 0) return -1; else if (status > 0) @@ -667,6 +679,7 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) mac = NULL; flag = NULL; macvlanmode = NULL; + vlanid = NULL; /* Keep the new value */ type = property->value; @@ -679,11 +692,13 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virPropertiesPtr properties) flag = property->value; else if (STREQ(property->key, "lxc.network.macvlan.mode")) macvlanmode = property->value; + else if (STREQ(property->key, "lxc.network.vlan.id")) + vlanid = property->value; } /* Add the last network definition found */ status = lxcAddNetworkDefinition(def, type, link, mac, flag, - macvlanmode); + macvlanmode, vlanid); if (status < 0) return -1; else if (status > 0) diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config new file mode 100644 index 0000000..574e975 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config @@ -0,0 +1,13 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = vlan +lxc.network.flags = up +lxc.network.link = eth0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.vlan.id = 2 + +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.mount = /var/lib/lxc/migrate_test/fstab diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml new file mode 100644 index 0000000..31e1513 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml @@ -0,0 +1,30 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>4035770</memory> + <currentMemory unit='KiB'>0</currentMemory> + <vcpu placement='static' current='0'>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/var/lib/lxc/migrate_test/rootfs'/> + <target dir='/'/> + </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='2017885' units='KiB'/> + <target dir='/run'/> + </filesystem> + <hostdev mode='capabilities' type='net'> + <source> + <interface>eth0.2</interface> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 60fdb01..86cbc3f 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -110,6 +110,7 @@ mymain(void) DO_TEST("nonetwork"); DO_TEST("physnetwork"); DO_TEST("macvlannetwork"); + DO_TEST("vlannetwork"); DO_TEST("idmap"); DO_TEST("memtune"); DO_TEST("cputune"); -- 1.8.5.2

On Tue, Jan 14, 2014 at 02:50:05PM +0100, Cédric Bosdonnat wrote:
The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent.
lxc.network.type = phys lxc.network.link = eth0.5
lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5
How does LXC deal with VLAN devices listed like this ? Would it automatically create the eth0.5 device in the second example ? Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, 2014-01-24 at 13:58 +0000, Daniel P. Berrange wrote:
On Tue, Jan 14, 2014 at 02:50:05PM +0100, Cédric Bosdonnat wrote:
The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent.
lxc.network.type = phys lxc.network.link = eth0.5
lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5
How does LXC deal with VLAN devices listed like this ? Would it automatically create the eth0.5 device in the second example ?
Yes, LXC automatically creates the eth0.5 in such a case. May be another RFE to file or patch? -- Cedric

On Fri, Jan 24, 2014 at 03:24:19PM +0100, Cedric Bosdonnat wrote:
On Fri, 2014-01-24 at 13:58 +0000, Daniel P. Berrange wrote:
On Tue, Jan 14, 2014 at 02:50:05PM +0100, Cédric Bosdonnat wrote:
The problem with VLAN is that the user still has to manually create the vlan interface on the host. Then the generated configuration will use it as a nerwork hostdev device. So the generated configurations of the following two fragments are equivalent.
lxc.network.type = phys lxc.network.link = eth0.5
lxc.network.type = vlan lxc.network.link = eth0 lxc.network.vlan.id = 5
How does LXC deal with VLAN devices listed like this ? Would it automatically create the eth0.5 device in the second example ?
Yes, LXC automatically creates the eth0.5 in such a case. May be another RFE to file or patch?
Yeah, probably worth an RFE Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Jan 14, 2014 at 02:49:49PM +0100, Cédric Bosdonnat wrote:
The aim of these patches is to provide users a way to easily convert existing LXC containers into libvirt LXC domains. This conversion is mostly based on the use of connectDomainXMLFromNative implementation, but there are small bits that will still need to be manually tweaked, like creating a VLAN interface on the host or precise the rootfs format for image files.
It would be useful to record details of features that are supported by the LXC tools, but not by libvirt LXC, so we can plan to close that gap. Perhaps just file bugs against libvirt for each missing feature. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Jan 14, 2014 at 02:49:49PM +0100, Cédric Bosdonnat wrote:
The aim of these patches is to provide users a way to easily convert existing LXC containers into libvirt LXC domains. This conversion is mostly based on the use of connectDomainXMLFromNative implementation, but there are small bits that will still need to be manually tweaked, like creating a VLAN interface on the host or precise the rootfs format for image files.
So overall this looks like a pretty good patch set to me. It should be very useful to people wishing to migrate to using libvirt for LXC. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Cedric Bosdonnat
-
Cédric Bosdonnat
-
Daniel P. Berrange