[libvirt] [PATCH v2 00/18] LXC configuration conversion to domain XML

This new version of the patchset, fixes all comments from Daniel. It also adds two more commits: one extending virConf to use it later in lxc_native.c and one for some documentation on the new feature and its limitations. Several RFEs have been filesd for this patchset: they are mentioned in the appropriate commit log, and I still hope to be able to provide patches for them later. Cédric Bosdonnat (18): Improve virConf parse to handle LXC config format 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 LXC: added some doc on domxml-from-native with mention of limitations .gitignore | 1 + docs/drvlxc.html.in | 34 +- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 1 + src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_driver.c | 31 + src/lxc/lxc_native.c | 883 +++++++++++++++++++++ src/lxc/lxc_native.h | 32 + src/util/virconf.c | 46 +- src/util/virconf.h | 10 + tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 7 + tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 35 + .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 + tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 + tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 + tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 + tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 + tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 + .../lxcconf2xml-macvlannetwork.config | 13 + .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 + tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 + tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 + .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 + tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 + tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 + .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 + tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 + tests/lxcconf2xmldata/lxcconf2xml-simple.config | 41 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 41 + .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 + tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 + tests/lxcconf2xmltest.c | 131 +++ 37 files changed, 1640 insertions(+), 5 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-fstab.config 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-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.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/lxcconf2xmltest.c -- 1.8.5.2

virConf now honours a VIR_CONF_FLAG_LXC_FORMAT flag to handle LXC configuration files. The differences are that property names can contain '.' character and values are all strings without any bounding quotes. Provide a new virConfWalk function calling a handler on all non-comment values. This function will be used by the LXC conversion code to loop over LXC configuration lines. --- src/libvirt_private.syms | 1 + src/util/virconf.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/util/virconf.h | 10 ++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3b3de15..d4cde24 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1121,6 +1121,7 @@ virConfNew; virConfReadFile; virConfReadMem; virConfSetValue; +virConfWalk; virConfWriteFile; virConfWriteMem; diff --git a/src/util/virconf.c b/src/util/virconf.c index e882d15..53d297e 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -429,6 +429,16 @@ virConfParseString(virConfParserCtxtPtr ctxt) if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; + } else if (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) { + base = ctxt->cur; + /* LXC config format doesn't support comments after the value */ + while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) + NEXT; + /* Reverse to exclude the trailing blanks from the value */ + while ((ctxt->cur > base) && (c_isblank(CUR))) + ctxt->cur--; + if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) + return NULL; } return ret; } @@ -454,7 +464,8 @@ virConfParseValue(virConfParserCtxtPtr ctxt) virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); return NULL; } - if ((CUR == '"') || (CUR == '\'')) { + if ((CUR == '"') || (CUR == '\'') || + (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT)) { type = VIR_CONF_STRING; str = virConfParseString(ctxt); if (str == NULL) @@ -561,7 +572,9 @@ virConfParseName(virConfParserCtxtPtr ctxt) while ((ctxt->cur < ctxt->end) && (c_isalnum(CUR) || (CUR == '_') || ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && - ((CUR == ':') || (CUR == '.') || (CUR == '-'))))) + ((CUR == ':') || (CUR == '.') || (CUR == '-'))) || + ((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) && + (CUR == '.')))) NEXT; if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; @@ -905,6 +918,35 @@ virConfSetValue(virConfPtr conf, return 0; } +/** + * virConfWalk: + * @conf: a configuration file handle + * @callback: the function to call to process each entry + * @data: obscure data passed to callback + * + * Walk over all entries of the configuration file and run the callback + * for each with entry name, value and the obscure data. + * + * Returns 0 on success, or -1 on failure. + */ +int virConfWalk(virConfPtr conf, + virConfWalkCallback callback, + void *data) +{ + virConfEntryPtr cur; + + if (!conf) + return 0; + + cur = conf->entries; + while (cur != NULL) { + if (cur->name && cur->value && + callback(cur->name, cur->value, data) < 0) + return -1; + cur = cur->next; + } + return 0; +} /** * virConfWriteFile: diff --git a/src/util/virconf.h b/src/util/virconf.h index 577af8c..320d83e 100644 --- a/src/util/virconf.h +++ b/src/util/virconf.h @@ -40,6 +40,9 @@ typedef enum { VIR_CONF_FLAG_VMX_FORMAT = 1, /* allow ':', '.' and '-' in names for compatibility with VMware VMX configuration file, but restrict allowed value types to string only */ + VIR_CONF_FLAG_LXC_FORMAT = 2, /* allow '.' in names for compatibility with LXC + configuration file, restricts allowed value types + to string only and don't expect quotes for values */ } virConfFlags; static inline const char * @@ -79,6 +82,10 @@ struct _virConfValue { typedef struct _virConf virConf; typedef virConf *virConfPtr; +typedef int (*virConfWalkCallback)(const char* name, + virConfValuePtr value, + void *data); + virConfPtr virConfNew (void); virConfPtr virConfReadFile (const char *filename, unsigned int flags); virConfPtr virConfReadMem (const char *memory, @@ -91,6 +98,9 @@ virConfValuePtr virConfGetValue (virConfPtr conf, int virConfSetValue (virConfPtr conf, const char *setting, virConfValuePtr value); +int virConfWalk(virConfPtr conf, + virConfWalkCallback callback, + void *data); int virConfWriteFile (const char *filename, virConfPtr conf); int virConfWriteMem (char *memory, -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:49AM +0100, Cédric Bosdonnat wrote:
virConf now honours a VIR_CONF_FLAG_LXC_FORMAT flag to handle LXC configuration files. The differences are that property names can contain '.' character and values are all strings without any bounding quotes.
Provide a new virConfWalk function calling a handler on all non-comment values. This function will be used by the LXC conversion code to loop over LXC configuration lines.
+/** + * virConfWalk: + * @conf: a configuration file handle + * @callback: the function to call to process each entry + * @data: obscure data passed to callback + * + * Walk over all entries of the configuration file and run the callback + * for each with entry name, value and the obscure data. + * + * Returns 0 on success, or -1 on failure. + */ +int virConfWalk(virConfPtr conf, + virConfWalkCallback callback, + void *data)
Nit-pick: s/data/opaque/ for more common naming convention here and in the header file decl later too.
+{ + virConfEntryPtr cur; + + if (!conf) + return 0; + + cur = conf->entries; + while (cur != NULL) { + if (cur->name && cur->value && + callback(cur->name, cur->value, data) < 0) + return -1; + cur = cur->next; + } + return 0; +}
/** * virConfWriteFile:
+typedef int (*virConfWalkCallback)(const char* name, + virConfValuePtr value, + void *data);
s/data/opaque/
+ virConfPtr virConfNew (void); virConfPtr virConfReadFile (const char *filename, unsigned int flags); virConfPtr virConfReadMem (const char *memory, @@ -91,6 +98,9 @@ virConfValuePtr virConfGetValue (virConfPtr conf, int virConfSetValue (virConfPtr conf, const char *setting, virConfValuePtr value); +int virConfWalk(virConfPtr conf, + virConfWalkCallback callback, + void *data);
s/data/opaque/ ACK with the nit-pick fixed. 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 :|

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. fstab files in lxc.mount lines will need to be merged into the configuration file as lxc.mount.entry. As we can't know the amount of memory of the host, we have to set a default value for max_balloon that users will probably want to adjust. --- .gitignore | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_driver.c | 31 +++++++ src/lxc/lxc_native.c | 86 +++++++++++++++++++ src/lxc/lxc_native.h | 32 +++++++ tests/Makefile.am | 7 +- tests/lxcconf2xmldata/lxcconf2xml-simple.config | 38 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 17 ++++ tests/lxcconf2xmltest.c | 107 ++++++++++++++++++++++++ 10 files changed, 320 insertions(+), 1 deletion(-) 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/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..f3a6f9e 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" @@ -993,6 +994,35 @@ cleanup: return ret; } +static char *lxcConnectDomainXMLFromNative(virConnectPtr conn, + const char *nativeFormat, + const char *nativeConfig, + unsigned int flags) +{ + char *xml = NULL; + virDomainDefPtr def = NULL; + + 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 (!(def = lxcParseConfigString(nativeConfig))) + goto cleanup; + + xml = virDomainDefFormat(def, 0); + +cleanup: + virDomainDefFree(def); + return xml; +} + /** * lxcDomainCreateWithFiles: * @dom: domain to start @@ -4760,6 +4790,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..723ebcf --- /dev/null +++ b/src/lxc/lxc_native.c @@ -0,0 +1,86 @@ +/* + * 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" +#include "util/virconf.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +virDomainDefPtr +lxcParseConfigString(const char *config) +{ + virDomainDefPtr vmdef = NULL; + virConfPtr properties = NULL; + virConfValuePtr value; + + if (!(properties = virConfReadMem(config, 0, VIR_CONF_FLAG_LXC_FORMAT))) + 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 = 64 * 1024; + + 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 (!(value = virConfGetValue(properties, "lxc.utsname")) || + !value->str || (VIR_STRDUP(vmdef->name, value->str) < 0)) + goto error; + if (!vmdef->name && (VIR_STRDUP(vmdef->name, "unnamed") < 0)) + goto error; + + goto cleanup; + +error: + virDomainDefFree(vmdef); + vmdef = NULL; + +cleanup: + virConfFree(properties); + + return vmdef; +} diff --git a/src/lxc/lxc_native.h b/src/lxc/lxc_native.h new file mode 100644 index 0000000..e43bd27 --- /dev/null +++ b/src/lxc/lxc_native.h @@ -0,0 +1,32 @@ +/* + * 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); + +#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..641e624 --- /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'>65536</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/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c new file mode 100644 index 0000000..9a840f9 --- /dev/null +++ b/tests/lxcconf2xmltest.c @@ -0,0 +1,107 @@ +#include <config.h> + +#include "testutils.h" + +#ifdef WITH_LXC + +# include "lxc/lxc_native.h" + +# define VIR_FROM_THIS VIR_FROM_NONE + +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) +{ + int ret = -1; + char *config = NULL; + char *expectxml = NULL; + char *actualxml = NULL; + virDomainDefPtr vmdef = NULL; + + if (virtTestLoadFile(configfile, &config) < 0) + goto fail; + if (virtTestLoadFile(xml, &expectxml) < 0) + goto fail; + + if (!(vmdef = lxcParseConfigString(config))) + 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); + virDomainDefFree(vmdef); + return ret; +} + +static int +testCompareXMLToConfigHelper(const void *data) +{ + int result = -1; + const char *name = data; + char *xml = NULL; + char *config = NULL; + + if (virAsprintf(&xml, "%s/lxcconf2xmldata/lxcconf2xml-%s.xml", + abs_srcdir, name) < 0 || + virAsprintf(&config, "%s/lxcconf2xmldata/lxcconf2xml-%s.config", + abs_srcdir, name) < 0) + goto cleanup; + + result = testCompareXMLToConfigFiles(xml, config); + +cleanup: + VIR_FREE(xml); + VIR_FREE(config); + 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 Thu, Jan 30, 2014 at 10:55:50AM +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
+virDomainDefPtr +lxcParseConfigString(const char *config) +{ + virDomainDefPtr vmdef = NULL; + virConfPtr properties = NULL; + virConfValuePtr value; + + if (!(properties = virConfReadMem(config, 0, VIR_CONF_FLAG_LXC_FORMAT))) + 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 = 64 * 1024;
I can't remember if the 'max_balloon' is a mandatory setting or not. If it isn't, perhaps we can just leave it out entirely.
diff --git a/src/lxc/lxc_native.h b/src/lxc/lxc_native.h new file mode 100644 index 0000000..e43bd27 --- /dev/null +++ b/src/lxc/lxc_native.h
+ +# define LXC_CONFIG_FORMAT "lxc"
I wonder if we should call this 'lxc-tools' just to make it a little more precise - bare 'lxc' is such an overloaded term these days. ACK modulo the 2 questions. 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 Daniel, On Tue, 2014-02-04 at 12:17 +0000, Daniel P. Berrange wrote:
On Thu, Jan 30, 2014 at 10:55:50AM +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
+virDomainDefPtr +lxcParseConfigString(const char *config) +{ + virDomainDefPtr vmdef = NULL; + virConfPtr properties = NULL; + virConfValuePtr value; + + if (!(properties = virConfReadMem(config, 0, VIR_CONF_FLAG_LXC_FORMAT))) + 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 = 64 * 1024;
I can't remember if the 'max_balloon' is a mandatory setting or not. If it isn't, perhaps we can just leave it out entirely.
It is mandatory, that's why I picked the same default value than the one in the qemu argv conversion code.
diff --git a/src/lxc/lxc_native.h b/src/lxc/lxc_native.h new file mode 100644 index 0000000..e43bd27 --- /dev/null +++ b/src/lxc/lxc_native.h
+ +# define LXC_CONFIG_FORMAT "lxc"
I wonder if we should call this 'lxc-tools' just to make it a little more precise - bare 'lxc' is such an overloaded term these days.
Indeed, lxc-tools would help disambiguate the thing. -- 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 | 69 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 73 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 723ebcf..86d0dd3 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -31,6 +31,72 @@ #define VIR_FROM_THIS VIR_FROM_LXC + +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, + virConfPtr properties) +{ + char *fssrc = NULL; + char *fsdst = NULL; + int type = VIR_DOMAIN_FS_TYPE_MOUNT; + virConfValuePtr value; + + if (!(value = virConfGetValue(properties, "lxc.rootfs")) || + !value->str || + (VIR_STRDUP(fssrc, value->str) < 0) || + VIR_STRDUP(fsdst, "/") < 0) + goto error; + + if (STRPREFIX(fssrc, "/dev/")) + 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) { @@ -73,6 +139,9 @@ lxcParseConfigString(const char *config) if (!vmdef->name && (VIR_STRDUP(vmdef->name, "unnamed") < 0)) 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 641e624..eebcb4e 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 Thu, Jan 30, 2014 at 10:55:51AM +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 | 69 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 4 ++ 2 files changed, 73 insertions(+)
ACK 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 relative size and default 50% size values aren't supported as we have no idea of the available memory at the conversion time. --- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_native.c | 245 +++++++++++++++++++++++- tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 ++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 4 +- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 9 + tests/lxcconf2xmltest.c | 60 +++--- 7 files changed, 330 insertions(+), 29 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index c6bdc8c..f08dbc2 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -744,7 +744,7 @@ static const virLXCBasicMountInfo lxcBasicMounts[] = { }; -static bool lxcIsBasicMountLocation(const char *path) +bool lxcIsBasicMountLocation(const char *path) { size_t i; diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index e74a7d7..67292ab 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -71,4 +71,6 @@ virArch lxcContainerGetAlt32bitArch(virArch arch); int lxcContainerChown(virDomainDefPtr def, const char *path); +bool lxcIsBasicMountLocation(const char *path); + #endif /* LXC_CONTAINER_H */ diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 86d0dd3..31c1194 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -21,10 +21,13 @@ */ #include <config.h> +#include <stdio.h> #include "internal.h" +#include "lxc_container.h" #include "lxc_native.h" #include "util/viralloc.h" +#include "util/virfile.h" #include "util/virlog.h" #include "util/virstring.h" #include "util/virconf.h" @@ -33,7 +36,11 @@ static virDomainFSDefPtr -lxcCreateFSDef(int type, char *src, char* dst) +lxcCreateFSDef(int type, + char *src, + char* dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr def; @@ -44,16 +51,124 @@ lxcCreateFSDef(int type, char *src, char* dst) def->accessmode = VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH; def->src = src; def->dst = dst; + def->readonly = readonly; + def->usage = usage; return def; } +typedef struct _lxcFstab lxcFstab; +typedef lxcFstab *lxcFstabPtr; +struct _lxcFstab { + lxcFstabPtr next; + char *src; + char *dst; + char *type; + char *options; +}; + +static void +lxcFstabFree(lxcFstabPtr fstab) +{ + while (fstab) { + lxcFstabPtr next = NULL; + next = fstab->next; + + VIR_FREE(fstab->src); + VIR_FREE(fstab->dst); + VIR_FREE(fstab->type); + VIR_FREE(fstab->options); + VIR_FREE(fstab); + + fstab = next; + } +} + +static char ** lxcStringSplit(const char *string) +{ + char *tmp; + size_t i; + size_t ntokens = 0; + char **parts; + char **result = NULL; + + if (VIR_STRDUP(tmp, string) < 0) + return NULL; + + /* Replace potential \t by a space */ + for (i = 0; tmp[i]; i++) { + if (tmp[i] == '\t') + tmp[i] = ' '; + } + + parts = virStringSplit(tmp, " ", 0); + for (i = 0; parts[i]; i++) { + if (STREQ(parts[i], "")) + continue; + + if (VIR_EXPAND_N(result, ntokens, 1) < 0) + goto error; + + if (VIR_STRDUP(result[ntokens-1], parts[i]) < 0) + goto error; + } + + /* Append NULL element */ + if (VIR_EXPAND_N(result, ntokens, 1) < 0) + goto error; + + VIR_FREE(tmp); + virStringFreeList(parts); + return result; + +error: + VIR_FREE(tmp); + virStringFreeList(parts); + virStringFreeList(result); + return NULL; +} + +static lxcFstabPtr +lxcParseFstabLine(char *fstabLine) +{ + lxcFstabPtr fstab = NULL; + char **parts; + + if (!fstabLine || VIR_ALLOC(fstab) < 0) + return NULL; + + parts = lxcStringSplit(fstabLine); + + if (!parts[0] || !parts[1] || !parts[2] || !parts[3]) + goto error; + + if (VIR_STRDUP(fstab->src, parts[0]) < 0 || + VIR_STRDUP(fstab->dst, parts[1]) < 0 || + VIR_STRDUP(fstab->type, parts[2]) < 0 || + VIR_STRDUP(fstab->options, parts[3]) < 0) + goto error; + + virStringFreeList(parts); + + return fstab; + +error: + lxcFstabFree(fstab); + virStringFreeList(parts); + return NULL; +} + static int -lxcAddFSDef(virDomainDefPtr def, int type, char *src, char *dst) +lxcAddFSDef(virDomainDefPtr def, + int type, + char *src, + char *dst, + bool readonly, + unsigned long long usage) { virDomainFSDefPtr fsDef = NULL; - if (!(fsDef = lxcCreateFSDef(type, src, dst))) + if (!(fsDef = lxcCreateFSDef(type, src, dst, readonly, usage))) goto error; if (VIR_EXPAND_N(def->fss, def->nfss, 1) < 0) @@ -86,7 +201,7 @@ lxcSetRootfs(virDomainDefPtr def, type = VIR_DOMAIN_FS_TYPE_BLOCK; - if (lxcAddFSDef(def, type, fssrc, fsdst) < 0) + if (lxcAddFSDef(def, type, fssrc, fsdst, false, 0) < 0) goto error; return 0; @@ -97,6 +212,113 @@ error: return -1; } +static int +lxcConvertSize(const char *size, unsigned long long *value) +{ + char *unit = NULL; + + /* Split the string into value and unit */ + if (virStrToLong_ull(size, &unit, 10, value) < 0) + goto error; + + if (STREQ(unit, "%")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("can't convert relative size: '%s'"), + size); + return -1; + } else if (virScaleInteger(value, unit, 1, ULLONG_MAX) < 0) + goto error; + + return 0; + +error: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to convert size: '%s'"), + size); + return -1; +} + +static int +lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) +{ + char *src = NULL; + char *dst = NULL; + char **options = virStringSplit(fstab->options, ",", 0); + bool readonly; + int type = VIR_DOMAIN_FS_TYPE_MOUNT; + unsigned long long usage = 0; + + if (fstab->dst[0] != '/') { + if (virAsprintf(&dst, "/%s", fstab->dst) < 0) + goto error; + } else if (VIR_STRDUP(dst, fstab->dst) < 0) + goto error; + + /* Check that we don't add basic mounts */ + if (lxcIsBasicMountLocation(dst)) { + VIR_FREE(dst); + return 0; + } + + if (STREQ(fstab->type, "tmpfs")) { + char *sizeStr = NULL; + size_t i; + type = VIR_DOMAIN_FS_TYPE_RAM; + + for (i = 0; options[i]; i++) { + if ((sizeStr = STRSKIP(options[i], "size="))) { + if (lxcConvertSize(sizeStr, &usage) < 0) + goto error; + break; + } + } + if (!sizeStr) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing tmpfs size, set the size option")); + goto error; + } + } else if (VIR_STRDUP(src, fstab->src) < 0) + goto error; + + /* Do we have ro in options? */ + readonly = virStringArrayHasString(options, "ro"); + + if (lxcAddFSDef(def, type, src, dst, readonly, usage) < 0) + goto error; + + + return 1; + +error: + VIR_FREE(dst); + VIR_FREE(src); + virStringFreeList(options); + return -1; +} + +static int +lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data) +{ + int ret = 0; + lxcFstabPtr fstabLine; + virDomainDefPtr def = data; + + /* We only care about lxc.mount.entry lines */ + if (STRNEQ(name, "lxc.mount.entry")) + return 0; + + fstabLine = lxcParseFstabLine(value->str); + + if (!fstabLine) + return -1; + + if (lxcAddFstabLine(def, fstabLine) < 0) + ret = -1; + + lxcFstabFree(fstabLine); + return ret; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -115,6 +337,7 @@ lxcParseConfigString(const char *config) _("failed to generate uuid")); goto error; } + vmdef->id = -1; vmdef->mem.max_balloon = 64 * 1024; @@ -127,6 +350,8 @@ lxcParseConfigString(const char *config) * minimum required to make XML parsing pass */ vmdef->maxvcpus = 1; + vmdef->nfss = 0; + if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error; @@ -142,6 +367,18 @@ lxcParseConfigString(const char *config) if (lxcSetRootfs(vmdef, properties) < 0) goto error; + /* Look for fstab: we shouldn't have it */ + if (virConfGetValue(properties, "lxc.mount")) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("lxc.mount found, use lxc.mount.entry lines instead")); + goto error; + } + + /* Loop over lxc.mount.entry to add filesystem devices for them */ + value = virConfGetValue(properties, "lxc.mount.entry"); + if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-fstab.config b/tests/lxcconf2xmldata/lxcconf2xml-fstab.config new file mode 100644 index 0000000..8c03c22 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-fstab.config @@ -0,0 +1,37 @@ +# Template used to create this container: opensuse +# Template script checksum (SHA-1): 27307e0a95bd81b2c0bd82d6f87fdbe83be075ef + +lxc.network.type = veth +lxc.network.flags = up +lxc.network.link = virbr0 +lxc.network.hwaddr = 02:00:15:8f:05:c1 +lxc.network.name = eth0 + +#remove next line if host DNS configuration should not be available to container +lxc.mount = /var/lib/lxc/migrate_test/fstab +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.tty = 2 +lxc.pts = 1024 +lxc.cap.drop = sys_module mac_admin mac_override mknod + +# When using LXC with apparmor, uncomment the next line to run unconfined: +#lxc.aa_profile = unconfined + +lxc.cgroup.devices.deny = a +# /dev/null and zero +lxc.cgroup.devices.allow = c 1:3 rwm +lxc.cgroup.devices.allow = c 1:5 rwm +# consoles +lxc.cgroup.devices.allow = c 5:1 rwm +lxc.cgroup.devices.allow = c 5:0 rwm +lxc.cgroup.devices.allow = c 4:0 rwm +lxc.cgroup.devices.allow = c 4:1 rwm +# /dev/{,u}random +lxc.cgroup.devices.allow = c 1:9 rwm +lxc.cgroup.devices.allow = c 1:8 rwm +lxc.cgroup.devices.allow = c 136:* rwm +lxc.cgroup.devices.allow = c 5:2 rwm +# rtc +lxc.cgroup.devices.allow = c 254:0 rwm diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.config b/tests/lxcconf2xmldata/lxcconf2xml-simple.config index 12428bb..f75e8fc 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.config +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -8,13 +8,15 @@ lxc.network.hwaddr = 02:00:15:8f:05:c1 lxc.network.name = eth0 #remove next line if host DNS configuration should not be available to container +lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0 +lxc.mount.entry = sysfs sys sysfs defaults 0 0 +lxc.mount.entry = tmpfs run tmpfs size=8m,mode=0755,nodev,nosuid 0 0 lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,ro 0 0 lxc.rootfs = /var/lib/lxc/migrate_test/rootfs lxc.utsname = migrate_test lxc.autodev=1 lxc.tty = 2 lxc.pts = 1024 -lxc.mount = /var/lib/lxc/migrate_test/fstab lxc.cap.drop = sys_module mac_admin mac_override mknod # When using LXC with apparmor, uncomment the next line to run unconfined: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index eebcb4e..fadbdca 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -17,5 +17,14 @@ <source dir='/var/lib/lxc/migrate_test/rootfs'/> <target dir='/'/> </filesystem> + <filesystem type='ram' accessmode='passthrough'> + <source usage='8192' units='KiB'/> + <target dir='/run'/> + </filesystem> + <filesystem type='mount' accessmode='passthrough'> + <source dir='/etc/resolv.conf'/> + <target dir='/etc/resolv.conf'/> + <readonly/> + </filesystem> </devices> </domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 9a840f9..c4b21ec 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -18,7 +18,8 @@ blankProblemElements(char *data) static int testCompareXMLToConfigFiles(const char *xml, - const char *configfile) + const char *configfile, + bool expectError) { int ret = -1; char *config = NULL; @@ -28,22 +29,26 @@ testCompareXMLToConfigFiles(const char *xml, if (virtTestLoadFile(configfile, &config) < 0) goto fail; - if (virtTestLoadFile(xml, &expectxml) < 0) - goto fail; - if (!(vmdef = lxcParseConfigString(config))) + vmdef = lxcParseConfigString(config); + if ((vmdef && expectError) || (!vmdef && !expectError)) goto fail; - if (!(actualxml = virDomainDefFormat(vmdef, 0))) - goto fail; + if (vmdef) { + if (!(actualxml = virDomainDefFormat(vmdef, 0))) + goto fail; - if (blankProblemElements(expectxml) < 0 || - blankProblemElements(actualxml) < 0) - goto fail; + if (virtTestLoadFile(xml, &expectxml) < 0) + goto fail; - if (STRNEQ(expectxml, actualxml)) { - virtTestDifference(stderr, expectxml, actualxml); - goto fail; + if (blankProblemElements(expectxml) < 0 || + blankProblemElements(actualxml) < 0) + goto fail; + + if (STRNEQ(expectxml, actualxml)) { + virtTestDifference(stderr, expectxml, actualxml); + goto fail; + } } ret = 0; @@ -56,21 +61,26 @@ fail: return ret; } +struct testInfo { + const char *name; + bool expectError; +}; + static int testCompareXMLToConfigHelper(const void *data) { int result = -1; - const char *name = data; + const struct testInfo *info = data; char *xml = NULL; char *config = NULL; if (virAsprintf(&xml, "%s/lxcconf2xmldata/lxcconf2xml-%s.xml", - abs_srcdir, name) < 0 || + abs_srcdir, info->name) < 0 || virAsprintf(&config, "%s/lxcconf2xmldata/lxcconf2xml-%s.config", - abs_srcdir, name) < 0) + abs_srcdir, info->name) < 0) goto cleanup; - result = testCompareXMLToConfigFiles(xml, config); + result = testCompareXMLToConfigFiles(xml, config, info->expectError); cleanup: VIR_FREE(xml); @@ -83,13 +93,17 @@ mymain(void) { int ret = EXIT_SUCCESS; -# define DO_TEST(name) \ - if (virtTestRun("LXC Native-2-XML " name, \ - testCompareXMLToConfigHelper, \ - name) < 0) \ - ret = EXIT_FAILURE - - DO_TEST("simple"); +# define DO_TEST(name, expectError) \ + do { \ + const struct testInfo info = { name, expectError }; \ + if (virtTestRun("LXC Native-2-XML " name, \ + testCompareXMLToConfigHelper, \ + &info) < 0) \ + ret = EXIT_FAILURE; \ + } while (0) + + DO_TEST("simple", false); + DO_TEST("fstab", true); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:52AM +0100, Cédric Bosdonnat wrote:
Tmpfs relative size and default 50% size values aren't supported as we have no idea of the available memory at the conversion time. --- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_container.h | 2 + src/lxc/lxc_native.c | 245 +++++++++++++++++++++++- tests/lxcconf2xmldata/lxcconf2xml-fstab.config | 37 ++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 4 +- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 9 + tests/lxcconf2xmltest.c | 60 +++--- 7 files changed, 330 insertions(+), 29 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-fstab.config
+static int +lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) +{ + char *src = NULL; + char *dst = NULL; + char **options = virStringSplit(fstab->options, ",", 0); + bool readonly; + int type = VIR_DOMAIN_FS_TYPE_MOUNT; + unsigned long long usage = 0; + + if (fstab->dst[0] != '/') { + if (virAsprintf(&dst, "/%s", fstab->dst) < 0) + goto error; + } else if (VIR_STRDUP(dst, fstab->dst) < 0) + goto error;
Nit-pick: i think it'd be slightly clearer if you did } else { if (VIR_STRDUP(dst, fstab->dst) < 0) goto error; } because we prefer that if/else both match in their use of {}
+ + /* Check that we don't add basic mounts */ + if (lxcIsBasicMountLocation(dst)) { + VIR_FREE(dst); + return 0; + } + + if (STREQ(fstab->type, "tmpfs")) { + char *sizeStr = NULL; + size_t i; + type = VIR_DOMAIN_FS_TYPE_RAM; + + for (i = 0; options[i]; i++) { + if ((sizeStr = STRSKIP(options[i], "size="))) { + if (lxcConvertSize(sizeStr, &usage) < 0) + goto error; + break; + } + } + if (!sizeStr) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing tmpfs size, set the size option")); + goto error; + } + } else if (VIR_STRDUP(src, fstab->src) < 0) + goto error;
And here too - add {} in the 'else { ..strdup bits.. }' ACK with the nitpick fixed. 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. LXC will also define a 'none' network type in its 1.0.0 version that fits libvirt LXC driver's default. --- src/lxc/lxc_native.c | 55 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 ++ tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 ++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 ++++++++++ tests/lxcconf2xmltest.c | 2 + 6 files changed, 109 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml 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 31c1194..eb23f73 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -319,6 +319,57 @@ lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data) return ret; } +typedef struct { + char *type; + bool privnet; + size_t networks; +} lxcNetworkParseData; + +static int +lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) +{ + lxcNetworkParseData *parseData = data; + + if (STREQ(name, "lxc.network.type")) { + if (parseData->type != NULL && STREQ(parseData->type, "none")) + parseData->privnet = false; + else if ((parseData->type != NULL) && + STRNEQ(parseData->type, "empty") && + STRNEQ(parseData->type, "")) { + parseData->networks++; + } + + /* Start a new network interface config */ + parseData->type = NULL; + + /* Keep the new value */ + parseData->type = value->str; + } + return 0; +} + +static int +lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) +{ + lxcNetworkParseData data = {NULL, true, 0}; + + virConfWalk(properties, lxcNetworkWalkCallback, &data); + + if ((data.type != NULL) && STREQ(data.type, "none")) + data.privnet = false; + else if ((data.type != NULL) && STRNEQ(data.type, "empty") && + STRNEQ(data.type, "")) { + data.networks++; + } + + if (data.networks == 0 && data.privnet) { + /* 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) { @@ -379,6 +430,10 @@ lxcParseConfigString(const char *config) if (virConfWalk(properties, lxcFstabWalkCallback, vmdef) < 0) goto error; + /* Network configuration */ + if (lxcConvertNetworkSettings(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config new file mode 100644 index 0000000..c1bb9a6 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config @@ -0,0 +1,4 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 +lxc.network.type = none diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml new file mode 100644 index 0000000..eebcb4e --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml @@ -0,0 +1,21 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + </devices> +</domain> diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config new file mode 100644 index 0000000..b6fbe1d --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config @@ -0,0 +1,3 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml new file mode 100644 index 0000000..511e3dd --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml @@ -0,0 +1,24 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index c4b21ec..50041a5 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -104,6 +104,8 @@ mymain(void) DO_TEST("simple", false); DO_TEST("fstab", true); + DO_TEST("nonetwork", false); + DO_TEST("nonenetwork", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:53AM +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. LXC will also define a 'none' network type in its 1.0.0 version that fits libvirt LXC driver's default. --- src/lxc/lxc_native.c | 55 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-nonenetwork.config | 4 ++ tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 21 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config | 3 ++ tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 24 ++++++++++ tests/lxcconf2xmltest.c | 2 + 6 files changed, 109 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml
ACK 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 :|

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, see rhbz#1059624 * lxc.network.name, see rhbz#1059630 --- src/lxc/lxc_native.c | 114 ++++++++++++++++++++++++--- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index eb23f73..c4238a8 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -319,8 +319,80 @@ lxcFstabWalkCallback(const char* name, virConfValuePtr value, void * data) return ret; } +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, "") || + STREQ(type, "none")) + 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; +} + typedef struct { + virDomainDefPtr def; char *type; + char *link; + char *mac; + char *flag; bool privnet; size_t networks; } lxcNetworkParseData; @@ -329,38 +401,56 @@ static int lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) { lxcNetworkParseData *parseData = data; + int status; if (STREQ(name, "lxc.network.type")) { - if (parseData->type != NULL && STREQ(parseData->type, "none")) - parseData->privnet = false; - else if ((parseData->type != NULL) && - STRNEQ(parseData->type, "empty") && - STRNEQ(parseData->type, "")) { + /* Store the previous NIC */ + status = lxcAddNetworkDefinition(parseData->def, parseData->type, + parseData->link, parseData->mac, + parseData->flag); + if (status < 0) + return -1; + else if (status > 0) parseData->networks++; - } + else if (parseData->type != NULL && STREQ(parseData->type, "none")) + parseData->privnet = false; /* Start a new network interface config */ parseData->type = NULL; + parseData->link = NULL; + parseData->mac = NULL; + parseData->flag = NULL; /* Keep the new value */ parseData->type = value->str; } + else if (STREQ(name, "lxc.network.link")) + parseData->link = value->str; + else if (STREQ(name, "lxc.network.hwaddr")) + parseData->mac = value->str; + else if (STREQ(name, "lxc.network.flags")) + parseData->flag = value->str; + return 0; } static int lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) { - lxcNetworkParseData data = {NULL, true, 0}; + int status; + lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, true, 0}; virConfWalk(properties, lxcNetworkWalkCallback, &data); - if ((data.type != NULL) && STREQ(data.type, "none")) - data.privnet = false; - else if ((data.type != NULL) && STRNEQ(data.type, "empty") && - STRNEQ(data.type, "")) { + /* Add the last network definition found */ + status = lxcAddNetworkDefinition(def, data.type, data.link, + data.mac, data.flag); + if (status < 0) + return -1; + else if (status > 0) data.networks++; - } + else if (data.type != NULL && STREQ(data.type, "none")) + data.privnet = false; if (data.networks == 0 && data.privnet) { /* When no network type is provided LXC only adds loopback */ diff --git a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml index fadbdca..75c3b28 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.xml +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.xml @@ -26,5 +26,10 @@ <target dir='/etc/resolv.conf'/> <readonly/> </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 Thu, Jan 30, 2014 at 10:55:54AM +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, see rhbz#1059624 * lxc.network.name, see rhbz#1059630 --- src/lxc/lxc_native.c | 114 ++++++++++++++++++++++++--- tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 5 ++ 2 files changed, 107 insertions(+), 12 deletions(-)
ACK 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 +++++++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 +++ tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 +++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 72 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 c4238a8..ad33845 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -360,6 +360,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, @@ -368,22 +388,36 @@ lxcAddNetworkDefinition(virDomainDefPtr def, const char *flag) { virDomainNetDefPtr net = NULL; + virDomainHostdevDefPtr hostdev = NULL; if ((type == NULL) || STREQ(type, "empty") || STREQ(type, "") || STREQ(type, "none")) return 0; - if (!(net = lxcCreateNetDef(type, link, mac, flag))) - goto error; + if (type != NULL && STREQ(type, "phys")) { + if (!link || + !(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..63a4aa1 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config @@ -0,0 +1,6 @@ +lxc.network.type = phys +lxc.network.link = eth0 + +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml new file mode 100644 index 0000000..35a2a96 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml @@ -0,0 +1,26 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + <hostdev mode='capabilities' type='net'> + <source> + <interface>eth0</interface> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 50041a5..c888b42 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -106,6 +106,7 @@ mymain(void) DO_TEST("fstab", true); DO_TEST("nonetwork", false); DO_TEST("nonenetwork", false); + DO_TEST("physnetwork", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:55AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 +++++++++++++++++++--- .../lxcconf2xmldata/lxcconf2xml-physnetwork.config | 6 +++ tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 26 +++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml
ACK 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-simple.xml | 6 ++++ 2 files changed, 50 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index ad33845..9d9ccb1 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -494,6 +494,46 @@ lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) return 0; } +static int +lxcCreateConsoles(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + int nbttys = 0; + virDomainChrDefPtr console; + size_t i; + + if (!(value = virConfGetValue(properties, "lxc.tty")) || !value->str) + return 0; + + if (virStrToLong_i(value->str, NULL, 10, &nbttys) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to parse int: '%s'"), + value->str); + 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) { @@ -558,6 +598,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 75c3b28..711e0d9 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 Thu, Jan 30, 2014 at 10:55:56AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 44 ++++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 6 ++++ 2 files changed, 50 insertions(+)
ACK 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 | 47 +++++++++++++++++----- .../lxcconf2xml-macvlannetwork.config | 13 ++++++ .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+), 10 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 9d9ccb1..9ddbcc7 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -323,9 +323,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; @@ -337,9 +339,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; @@ -348,9 +352,20 @@ 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 (!link || 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, "bridge")) + net->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE; + else + VIR_WARN("Unknown macvlan type: %s", macvlanmode); } return net; @@ -385,7 +400,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; @@ -405,7 +421,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) @@ -427,6 +443,7 @@ typedef struct { char *link; char *mac; char *flag; + char *macvlanmode; bool privnet; size_t networks; } lxcNetworkParseData; @@ -441,7 +458,9 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) /* Store the previous NIC */ status = lxcAddNetworkDefinition(parseData->def, parseData->type, parseData->link, parseData->mac, - parseData->flag); + parseData->flag, + parseData->macvlanmode); + if (status < 0) return -1; else if (status > 0) @@ -454,6 +473,7 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) parseData->link = NULL; parseData->mac = NULL; parseData->flag = NULL; + parseData->macvlanmode = NULL; /* Keep the new value */ parseData->type = value->str; @@ -464,6 +484,12 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) parseData->mac = value->str; else if (STREQ(name, "lxc.network.flags")) parseData->flag = value->str; + else if (STREQ(name, "lxc.network.macvlan.mode")) + parseData->macvlanmode = value->str; + else if (STRPREFIX(name, "lxc.network")) + VIR_WARN("Unhandled network property: %s = %s", + name, + value->str); return 0; } @@ -472,13 +498,14 @@ static int lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) { int status; - lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, true, 0}; + lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, NULL, true, 0}; virConfWalk(properties, lxcNetworkWalkCallback, &data); /* Add the last network definition found */ status = lxcAddNetworkDefinition(def, data.type, data.link, - data.mac, data.flag); + data.mac, data.flag, + data.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..7c96bfa --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config @@ -0,0 +1,13 @@ +# 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 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml new file mode 100644 index 0000000..aa0683a --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml @@ -0,0 +1,26 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + <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 c888b42..4e7dd58 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -107,6 +107,7 @@ mymain(void) DO_TEST("nonetwork", false); DO_TEST("nonenetwork", false); DO_TEST("physnetwork", false); + DO_TEST("macvlannetwork", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:57AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 47 +++++++++++++++++----- .../lxcconf2xml-macvlannetwork.config | 13 ++++++ .../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 26 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml
ACK 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 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 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 9ddbcc7..4cbc0e6 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -561,6 +561,45 @@ error: return -1; } +static int +lxcIdmapWalkCallback(const char *name, virConfValuePtr value, void *data) +{ + virDomainDefPtr def = data; + virDomainIdMapEntryPtr idmap = NULL; + char type; + unsigned long start, target, count; + + if (STRNEQ(name, "lxc.id_map") || !value->str) + return 0; + + if (sscanf(value->str, "%c %lu %lu %lu", &type, + &target, &start, &count) != 4) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid lxc.id_map: '%s'"), + value->str); + 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; + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -629,6 +668,10 @@ lxcParseConfigString(const char *config) if (lxcCreateConsoles(vmdef, properties) < 0) goto error; + /* lxc.id_map */ + if (virConfWalk(properties, lxcIdmapWalkCallback, vmdef) < 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..4c3657a --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-idmap.config @@ -0,0 +1,5 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test + +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..576c903 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-idmap.xml @@ -0,0 +1,28 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 4e7dd58..7042bdf 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST("nonenetwork", false); DO_TEST("physnetwork", false); DO_TEST("macvlannetwork", false); + DO_TEST("idmap", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:58AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 43 ++++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-idmap.config | 5 +++ tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 28 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 77 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-idmap.xml
+ + 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;
Style nit-pick - when one part of an if/else has {}, then all parts should have {}. ACK with style nitpick. 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 | 40 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 ++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 80 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 4cbc0e6..e79ab3c 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -600,6 +600,42 @@ lxcIdmapWalkCallback(const char *name, virConfValuePtr value, void *data) return 0; } +static int +lxcSetMemTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + unsigned long long size = 0; + + if ((value = virConfGetValue(properties, + "lxc.cgroup.memory.limit_in_bytes")) && + value->str && STRNEQ(value->str, "-1")) { + if (lxcConvertSize(value->str, &size) < 0) + return -1; + size = size / 1024; + def->mem.max_balloon = size; + def->mem.hard_limit = size; + } + + if ((value = virConfGetValue(properties, + "lxc.cgroup.memory.soft_limit_in_bytes")) && + value->str && STRNEQ(value->str, "-1")) { + if (lxcConvertSize(value->str, &size) < 0) + return -1; + + def->mem.soft_limit = size / 1024; + } + + if ((value = virConfGetValue(properties, + "lxc.cgroup.memory.memsw.limit_in_bytes")) && + value->str && STRNEQ(value->str, "-1")) { + if (lxcConvertSize(value->str, &size) < 0) + return -1; + + def->mem.swap_hard_limit = size / 1024; + } + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -672,6 +708,10 @@ lxcParseConfigString(const char *config) if (virConfWalk(properties, lxcIdmapWalkCallback, vmdef) < 0) goto error; + /* lxc.cgroup.memory.* */ + if (lxcSetMemTune(vmdef, properties) < 0) + goto error; + goto cleanup; error: diff --git a/tests/lxcconf2xmldata/lxcconf2xml-memtune.config b/tests/lxcconf2xmldata/lxcconf2xml-memtune.config new file mode 100644 index 0000000..ef07a51 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-memtune.config @@ -0,0 +1,10 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +# 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..0264356 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-memtune.xml @@ -0,0 +1,29 @@ +<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> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 7042bdf..3dd0a0b 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -109,6 +109,7 @@ mymain(void) DO_TEST("physnetwork", false); DO_TEST("macvlannetwork", false); DO_TEST("idmap", false); + DO_TEST("memtune", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:55:59AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 40 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.config | 10 ++++++ tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 29 +++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 80 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-memtune.xml
ACK 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 | 34 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 +++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 71 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 e79ab3c..37bcd29 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -636,6 +636,36 @@ lxcSetMemTune(virDomainDefPtr def, virConfPtr properties) return 0; } +static int +lxcSetCpuTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + + if ((value = virConfGetValue(properties, "lxc.cgroup.cpu.shares")) && + value->str && virStrToLong_ul(value->str, NULL, 10, + &def->cputune.shares) < 0) + goto error; + + if ((value = virConfGetValue(properties, + "lxc.cgroup.cpu.cfs_quota_us")) && + value->str && virStrToLong_ll(value->str, NULL, 10, + &def->cputune.quota) < 0) + goto error; + + if ((value = virConfGetValue(properties, + "lxc.cgroup.cpu.cfs_period_us")) && + value->str && virStrToLong_ull(value->str, NULL, 10, + &def->cputune.period) < 0) + goto error; + + return 0; + +error: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse integer: '%s'"), value->str); + return -1; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -712,6 +742,10 @@ lxcParseConfigString(const char *config) if (lxcSetMemTune(vmdef, properties) < 0) goto error; + /* 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..9797dec --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cputune.config @@ -0,0 +1,7 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +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..a511dcf --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cputune.xml @@ -0,0 +1,29 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 3dd0a0b..1148cd3 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -110,6 +110,7 @@ mymain(void) DO_TEST("macvlannetwork", false); DO_TEST("idmap", false); DO_TEST("memtune", false); + DO_TEST("cputune", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:56:00AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 34 ++++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.config | 7 +++++ tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 29 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 71 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cputune.xml
ACK 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 | 30 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 +++++ tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 +++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 64 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 37bcd29..e0a4769 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -666,6 +666,32 @@ error: return -1; } +static int +lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + + if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.cpus")) && + value->str) { + if (virBitmapParse(value->str, 0, &def->cpumask, + VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + + def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC; + } + + if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.mems")) && + value->str) { + def->numatune.memory.placement_mode = VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC; + def->numatune.memory.mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT; + if (virBitmapParse(value->str, 0, &def->numatune.memory.nodemask, + VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + } + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -746,6 +772,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..a550f57 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config @@ -0,0 +1,6 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +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..1b8fb0c --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml @@ -0,0 +1,27 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 1148cd3..6bee5c5 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -111,6 +111,7 @@ mymain(void) DO_TEST("idmap", false); DO_TEST("memtune", false); DO_TEST("cputune", false); + DO_TEST("cpusettune", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:56:01AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 30 ++++++++++++++++++++++ .../lxcconf2xmldata/lxcconf2xml-cpusettune.config | 6 +++++ tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 27 +++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 64 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml
ACK 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 | 63 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 7 +++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 35 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 106 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 e0a4769..346dbba 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -692,6 +692,65 @@ lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) return 0; } +static int +lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) +{ + char **parts = NULL; + virBlkioDevicePtr device = NULL; + virDomainDefPtr def = data; + + if (STRNEQ(name, "lxc.cgroup.blkio.device_weight") || !value->str) + return 0; + + if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid blkio.device_weight value: '%s'"), + value->str); + 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) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse integer: '%s'"), parts[1]); + goto error; + } + + virStringFreeList(parts); + + return 0; + +error: + if (parts) + virStringFreeList(parts); + return -1; +} + +static int +lxcSetBlkioTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + + if ((value = virConfGetValue(properties, "lxc.cgroup.blkio.weight")) && + value->str && virStrToLong_ui(value->str, NULL, 10, + &def->blkio.weight) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse integer: '%s'"), value->str); + return -1; + } + + if (virConfWalk(properties, lxcBlkioDeviceWalkCallback, def) < 0) + return -1; + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -776,6 +835,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..8083c71 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config @@ -0,0 +1,7 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +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..d2408f4 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -0,0 +1,35 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + </devices> +</domain> diff --git a/tests/lxcconf2xmltest.c b/tests/lxcconf2xmltest.c index 6bee5c5..77baf20 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -112,6 +112,7 @@ mymain(void) DO_TEST("memtune", false); DO_TEST("cputune", false); DO_TEST("cpusettune", false); + DO_TEST("blkiotune", false); return ret; } -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:56:02AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 63 ++++++++++++++++++++++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config | 7 +++ tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 35 ++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 106 insertions(+) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml
ACK
diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index e0a4769..346dbba 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -692,6 +692,65 @@ lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) return 0; }
+static int +lxcBlkioDeviceWalkCallback(const char *name, virConfValuePtr value, void *data) +{ + char **parts = NULL; + virBlkioDevicePtr device = NULL; + virDomainDefPtr def = data; + + if (STRNEQ(name, "lxc.cgroup.blkio.device_weight") || !value->str) + return 0; + + if ((!(parts = lxcStringSplit(value->str)) && (!parts[0] || !parts[1]))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid blkio.device_weight value: '%s'"), + value->str); + 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) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse integer: '%s'"), parts[1]); + goto error; + } + + virStringFreeList(parts); + + return 0; + +error: + if (parts) + virStringFreeList(parts); + return -1; +} + +static int +lxcSetBlkioTune(virDomainDefPtr def, virConfPtr properties) +{ + virConfValuePtr value; + + if ((value = virConfGetValue(properties, "lxc.cgroup.blkio.weight")) && + value->str && virStrToLong_ui(value->str, NULL, 10, + &def->blkio.weight) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse integer: '%s'"), value->str); + return -1; + } + + if (virConfWalk(properties, lxcBlkioDeviceWalkCallback, def) < 0) + return -1; + + return 0; +} + virDomainDefPtr lxcParseConfigString(const char *config) { @@ -776,6 +835,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..8083c71 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config @@ -0,0 +1,7 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +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..d2408f4 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -0,0 +1,35 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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>
Hmm, I don't think this is correct. The libvirt XML takes block paths like /dev/sda, rather than relative sysfs block paths. If this works, it is by luck rather than by design. 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, 2014-02-04 at 12:39 +0000, Daniel P. Berrange wrote:
diff --git a/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config new file mode 100644 index 0000000..8083c71 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.config @@ -0,0 +1,7 @@ +lxc.rootfs = /var/lib/lxc/migrate_test/rootfs +lxc.utsname = migrate_test +lxc.autodev=1 + +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..d2408f4 --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml @@ -0,0 +1,35 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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>
Hmm, I don't think this is correct. The libvirt XML takes block paths like /dev/sda, rather than relative sysfs block paths.
If this works, it is by luck rather than by design.
Then how could we safely map this? lxc.cgroup.blkio.device_weight = 8:0 300 AFAICT there is no way to guess a /dev/sda-like path from the major:minor values of the device... and since we can't assume we have the device around it's surely impossible to map this. So it's a best effort. If that doesn't work for some users, then they will have to convert manually. The other option we have is to extend the domain configuration to allow giving major and minor as input for the lxc driver (those are used anyway when setting the cgroup). -- Cedric

--- src/lxc/lxc_native.c | 9 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 1 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 346dbba..98a9e12 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -787,6 +787,15 @@ lxcParseConfigString(const char *config) if (VIR_STRDUP(vmdef->os.type, "exe") < 0) goto error; + if ((value = virConfGetValue(properties, "lxc.arch")) && value->str) { + virArch arch = virArchFromString(value->str); + if (arch == VIR_ARCH_NONE && STREQ(value->str, "x86")) + arch = VIR_ARCH_I686; + else if (arch == VIR_ARCH_NONE && STREQ(value->str, "amd64")) + arch = VIR_ARCH_X86_64; + vmdef->os.arch = arch; + } + 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 f75e8fc..b90abc1 100644 --- a/tests/lxcconf2xmldata/lxcconf2xml-simple.config +++ b/tests/lxcconf2xmldata/lxcconf2xml-simple.config @@ -14,6 +14,7 @@ lxc.mount.entry = tmpfs run tmpfs size=8m,mode=0755,nodev,nosuid 0 0 lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,ro 0 0 lxc.rootfs = /var/lib/lxc/migrate_test/rootfs lxc.utsname = migrate_test +lxc.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 711e0d9..6ec0f17 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 Thu, Jan 30, 2014 at 10:56:03AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 9 +++++++++ tests/lxcconf2xmldata/lxcconf2xml-simple.config | 1 + tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-)
ACK 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 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 98a9e12..cdf7c7c 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -280,6 +280,10 @@ lxcAddFstabLine(virDomainDefPtr def, lxcFstabPtr fstab) } else if (VIR_STRDUP(src, fstab->src) < 0) goto error; + /* Is it a block device that needs special favor? */ + if (STRPREFIX(fstab->src, "/dev/")) + type = VIR_DOMAIN_FS_TYPE_BLOCK; + /* Do we have ro in options? */ readonly = virStringArrayHasString(options, "ro"); -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:56:04AM +0100, Cédric Bosdonnat wrote:
--- src/lxc/lxc_native.c | 4 ++++ 1 file changed, 4 insertions(+)
ACK 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 (see rhbz#1059637). 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 | 28 ++++++++++++++++++---- .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 ++++++++++ tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 62 insertions(+), 5 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 cdf7c7c..3837803 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -405,22 +405,33 @@ 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, "") || STREQ(type, "none")) return 0; - if (type != NULL && STREQ(type, "phys")) { + isPhys = STREQ(type, "phys"); + isVlan = STREQ(type, "vlan"); + if (type != NULL && (isPhys || isVlan)) { if (!link || !(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; @@ -448,6 +459,7 @@ typedef struct { char *mac; char *flag; char *macvlanmode; + char *vlanid; bool privnet; size_t networks; } lxcNetworkParseData; @@ -463,7 +475,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) status = lxcAddNetworkDefinition(parseData->def, parseData->type, parseData->link, parseData->mac, parseData->flag, - parseData->macvlanmode); + parseData->macvlanmode, + parseData->vlanid); if (status < 0) return -1; @@ -478,6 +491,7 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) parseData->mac = NULL; parseData->flag = NULL; parseData->macvlanmode = NULL; + parseData->vlanid = NULL; /* Keep the new value */ parseData->type = value->str; @@ -490,6 +504,8 @@ lxcNetworkWalkCallback(const char *name, virConfValuePtr value, void *data) parseData->flag = value->str; else if (STREQ(name, "lxc.network.macvlan.mode")) parseData->macvlanmode = value->str; + else if (STREQ(name, "lxc.network.vlan.id")) + parseData->vlanid = value->str; else if (STRPREFIX(name, "lxc.network")) VIR_WARN("Unhandled network property: %s = %s", name, @@ -502,14 +518,16 @@ static int lxcConvertNetworkSettings(virDomainDefPtr def, virConfPtr properties) { int status; - lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, NULL, true, 0}; + lxcNetworkParseData data = {def, NULL, NULL, NULL, NULL, + NULL, NULL, true, 0}; virConfWalk(properties, lxcNetworkWalkCallback, &data); /* Add the last network definition found */ status = lxcAddNetworkDefinition(def, data.type, data.link, data.mac, data.flag, - data.macvlanmode); + data.macvlanmode, + data.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..327202c --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config @@ -0,0 +1,12 @@ +# 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 diff --git a/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml new file mode 100644 index 0000000..7d6d51b --- /dev/null +++ b/tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml @@ -0,0 +1,26 @@ +<domain type='lxc'> + <name>migrate_test</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>65536</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> + <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 77baf20..e799893 100644 --- a/tests/lxcconf2xmltest.c +++ b/tests/lxcconf2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST("nonenetwork", false); DO_TEST("physnetwork", false); DO_TEST("macvlannetwork", false); + DO_TEST("vlannetwork", false); DO_TEST("idmap", false); DO_TEST("memtune", false); DO_TEST("cputune", false); -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:56:05AM +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 (see rhbz#1059637).
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 | 28 ++++++++++++++++++---- .../lxcconf2xmldata/lxcconf2xml-vlannetwork.config | 12 ++++++++++ tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 26 ++++++++++++++++++++ tests/lxcconf2xmltest.c | 1 + 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.config create mode 100644 tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml
ACK 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 :|

--- docs/drvlxc.html.in | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/drvlxc.html.in b/docs/drvlxc.html.in index 0f3efb0..7f73084 100644 --- a/docs/drvlxc.html.in +++ b/docs/drvlxc.html.in @@ -555,7 +555,7 @@ and LXC. For further details about usage of virsh consult its manual page. </p> -<h3><a name="usageSave">Defining (saving) container configuration></a></h3> +<h3><a name="usageSave">Defining (saving) container configuration</a></h3> <p> The <code>virsh define</code> command takes an XML configuration @@ -702,5 +702,37 @@ host # virt-top -c lxc:/// </pre> +<h3><a name="usageConvert">Converting LXC container configuration</a></h3> + +<p> +The <code>virsh domxml-from-native</code> command can be used to convert +most of the LXC container configuration into a domain XML fragment +</p> + +<pre> +# virsh -c lxc:/// domxml-from-native lxc /var/lib/lxc/myguest/config +</pre> + +<p> +This conversion has some limitations due to the fact that the +domxml-from-native command output has to be independent of the host. Here +are a few things to take care of before converting: +</p> + +<ul> +<li> +Replace the fstab file referenced by <tt>lxc.mount</tt> by the corresponding +lxc.mount.entry lines. +</li> +<li> +Replace all relative sizes of tmpfs mount entries to absolute sizes. Also +make sure that tmpfs entries all have a size option (default is 50%). +</li> +<li> +Define <tt>lxc.cgroup.memory.limit_in_bytes</tt> to properly limit the memory +available to the container. The conversion will use 64MiB as the default. +</li> +</ul> + </body> </html> -- 1.8.5.2

On Thu, Jan 30, 2014 at 10:56:06AM +0100, Cédric Bosdonnat wrote:
--- docs/drvlxc.html.in | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)
ACK 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