diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index faa5e462d16521da08859d1029a1ba46013ff487..863377ca857325b2ed72331cfdfbc65d82021d3b 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -250,6 +250,28 @@ installation media source / kickstart file +

Container boot

+ +

+ When booting a domain using container based virtualization, instead + of a kernel / boot image, a path to the init binary is required, using + the init element. By default this will be launched with + no arguments. To specify the initial argv, use the initarg + element, repeated as many time as is required. The cmdline + element, if set will be used to provide an equivalent to /proc/cmdline + but will not effect init argv. +

+ +
+  <os>
+    <type arch='x86_64'>exe</type>
+    <init>/bin/systemd</init>
+    <initarg>--unit</initarg>
+    <initarg>emergency.service</initarg>
+  </os>
+    
+ +

SMBIOS System Information

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 1f5232ef15a765ffde59142bbe3d762f901e3771..730f3d8e8ba339d19f24d13a95eb1f5793f3e58d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -378,6 +378,11 @@ + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e235c13581d19e31e041e5f712da8b04178ae9bb..ea558bbcef81bc2944e94566d34c2d3fd17442bc 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1559,6 +1559,9 @@ void virDomainDefFree(virDomainDefPtr def) VIR_FREE(def->os.arch); VIR_FREE(def->os.machine); VIR_FREE(def->os.init); + for (i = 0 ; def->os.initargv && def->os.initargv[i] ; i++) + VIR_FREE(def->os.initargv[i]); + VIR_FREE(def->os.initargv); VIR_FREE(def->os.kernel); VIR_FREE(def->os.initrd); VIR_FREE(def->os.cmdline); @@ -8188,6 +8191,25 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } } def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt); + + if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0) { + goto error; + } + + if (VIR_ALLOC_N(def->os.initargv, n+1) < 0) + goto no_memory; + for (i = 0 ; i < n ; i++) { + if (!nodes[i]->children || + !nodes[i]->children->content) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("No data supplied for element")); + goto error; + } + if (!(def->os.initargv[i] = strdup((const char*)nodes[i]->children->content))) + goto no_memory; + } + def->os.initargv[n] = NULL; + VIR_FREE(nodes); } if (STREQ(def->os.type, "xen") || @@ -12171,6 +12193,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, char uuidstr[VIR_UUID_STRING_BUFLEN]; const char *type = NULL; int n, allones = 1; + int i; bool blkio = false; virCheckFlags(DUMPXML_FLAGS | @@ -12332,7 +12355,6 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAsprintf(buf, " %lld\n", def->cputune.quota); if (def->cputune.vcpupin) { - int i; for (i = 0; i < def->cputune.nvcpupin; i++) { virBufferAsprintf(buf, " cputune.vcpupin[i]->vcpuid); @@ -12408,6 +12430,9 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferEscapeString(buf, " %s\n", def->os.init); + for (i = 0 ; def->os.initargv && def->os.initargv[i] ; i++) + virBufferEscapeString(buf, " %s\n", + def->os.initargv[i]); virBufferEscapeString(buf, " %s\n", def->os.loader); virBufferEscapeString(buf, " %s\n", @@ -12462,7 +12487,6 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAddLit(buf, " \n"); if (def->features) { - int i; virBufferAddLit(buf, " \n"); for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) { if (def->features & (1 << i)) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 10030a494e0460665700ef0b60b1046186899c2d..3fcb02644c8e581677f02542d776dfb64c6a88a4 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1354,6 +1354,7 @@ struct _virDomainOSDef { int bootDevs[VIR_DOMAIN_BOOT_LAST]; int bootmenu; char *init; + char **initargv; char *kernel; char *initrd; char *cmdline; diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index bb64b606f73d13d6472f727768c69becf99c047f..0755b3cc5028bf7fefd6a65b11b655421ea83dcb 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -122,6 +122,9 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef) cmd = virCommandNew(vmDef->os.init); + if (vmDef->os.initargv && vmDef->os.initargv[0]) + virCommandAddArgSet(cmd, (const char **)vmDef->os.initargv); + virCommandAddEnvString(cmd, "PATH=/bin:/sbin"); virCommandAddEnvString(cmd, "TERM=linux"); virCommandAddEnvString(cmd, "container=lxc-libvirt"); diff --git a/tests/Makefile.am b/tests/Makefile.am index 4755a3e6ea2ae431513d104230dd53ae8aa724db..4a0686ff4bf524e78d88478ea94f51a785ed34e5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -60,6 +60,7 @@ EXTRA_DIST = \ domainsnapshotxml2xmlin \ domainsnapshotxml2xmlout \ interfaceschemadata \ + lxcxml2xmldata \ networkschematest \ networkxml2xmlin \ networkxml2xmlout \ @@ -115,6 +116,10 @@ check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \ qemumonitortest endif +if WITH_LXC +check_PROGRAMS += lxcxml2xmltest +endif + if WITH_OPENVZ check_PROGRAMS += openvzutilstest endif @@ -245,6 +250,10 @@ TESTS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest qemuargv2xmltest \ qemumonitortest endif +if WITH_LXC +TESTS += lxcxml2xmltest +endif + if WITH_OPENVZ TESTS += openvzutilstest endif @@ -383,6 +392,18 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c \ qemumonitortest.c testutilsqemu.c testutilsqemu.h endif +if WITH_LXC + +lxc_LDADDS = ../src/libvirt_driver_lxc.la + +lxcxml2xmltest_SOURCES = \ + lxcxml2xmltest.c testutilslxc.c testutilslxc.h \ + testutils.c testutils.h +lxcxml2xmltest_LDADD = $(lxc_LDADDS) $(LDADDS) +else +EXTRA_DIST += lxcxml2xmltest.c testutilslxc.c testutilslxc.h +endif + if WITH_OPENVZ openvzutilstest_SOURCES = \ openvzutilstest.c \ diff --git a/tests/lxcxml2xmldata/lxc-systemd.xml b/tests/lxcxml2xmldata/lxc-systemd.xml new file mode 100644 index 0000000000000000000000000000000000000000..bf239c25772c768dfc22b554648adcd68ca9c7fd --- /dev/null +++ b/tests/lxcxml2xmldata/lxc-systemd.xml @@ -0,0 +1,30 @@ + + demo + 8369f1ac-7e46-e869-4ca5-759d51478066 + 500000 + 500000 + 1 + + exe + /bin/systemd + --unit + emergency.service + + + destroy + restart + destroy + + + + + + + + + + + + + + diff --git a/tests/lxcxml2xmltest.c b/tests/lxcxml2xmltest.c new file mode 100644 index 0000000000000000000000000000000000000000..558bd012c955db690add94c8ac1bf019fca37805 --- /dev/null +++ b/tests/lxcxml2xmltest.c @@ -0,0 +1,141 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef WITH_LXC + +# include "internal.h" +# include "testutils.h" +# include "lxc/lxc_conf.h" +# include "testutilslxc.h" + +static virCapsPtr caps; + +static int +testCompareXMLToXMLFiles(const char *inxml, const char *outxml, bool live) +{ + char *inXmlData = NULL; + char *outXmlData = NULL; + char *actual = NULL; + int ret = -1; + virDomainDefPtr def = NULL; + + if (virtTestLoadFile(inxml, &inXmlData) < 0) + goto fail; + if (virtTestLoadFile(outxml, &outXmlData) < 0) + goto fail; + + if (!(def = virDomainDefParseString(caps, inXmlData, + 1 << VIR_DOMAIN_VIRT_LXC, + live ? 0 : VIR_DOMAIN_XML_INACTIVE))) + goto fail; + + if (!(actual = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE))) + goto fail; + + if (STRNEQ(outXmlData, actual)) { + virtTestDifference(stderr, outXmlData, actual); + goto fail; + } + + ret = 0; + fail: + VIR_FREE(inXmlData); + VIR_FREE(outXmlData); + VIR_FREE(actual); + virDomainDefFree(def); + return ret; +} + +struct testInfo { + const char *name; + int different; + bool inactive_only; +}; + +static int +testCompareXMLToXMLHelper(const void *data) +{ + const struct testInfo *info = data; + char *xml_in = NULL; + char *xml_out = NULL; + int ret = -1; + + if (virAsprintf(&xml_in, "%s/lxcxml2xmldata/lxc-%s.xml", + abs_srcdir, info->name) < 0 || + virAsprintf(&xml_out, "%s/lxcxml2xmloutdata/lxc-%s.xml", + abs_srcdir, info->name) < 0) + goto cleanup; + + if (info->different) { + ret = testCompareXMLToXMLFiles(xml_in, xml_out, false); + } else { + ret = testCompareXMLToXMLFiles(xml_in, xml_in, false); + } + if (!info->inactive_only) { + if (info->different) { + ret = testCompareXMLToXMLFiles(xml_in, xml_out, true); + } else { + ret = testCompareXMLToXMLFiles(xml_in, xml_in, true); + } + } + +cleanup: + VIR_FREE(xml_in); + VIR_FREE(xml_out); + return ret; +} + + +static int +mymain(void) +{ + int ret = 0; + + if ((caps = testLXCCapsInit()) == NULL) + return (EXIT_FAILURE); + +# define DO_TEST_FULL(name, is_different, inactive) \ + do { \ + const struct testInfo info = {name, is_different, inactive}; \ + if (virtTestRun("LXC XML-2-XML " name, \ + 1, testCompareXMLToXMLHelper, &info) < 0) \ + ret = -1; \ + } while (0) + +# define DO_TEST(name) \ + DO_TEST_FULL(name, 0, false) + +# define DO_TEST_DIFFERENT(name) \ + DO_TEST_FULL(name, 1, false) + + /* Unset or set all envvars here that are copied in lxcdBuildCommandLine + * using ADD_ENV_COPY, otherwise these tests may fail due to unexpected + * values for these envvars */ + setenv("PATH", "/bin", 1); + + DO_TEST("systemd"); + + virCapabilitiesFree(caps); + + return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +VIRT_TEST_MAIN(mymain) + +#else +# include "testutils.h" + +int +main(void) +{ + return EXIT_AM_SKIP; +} + +#endif /* WITH_LXC */ diff --git a/tests/testutilslxc.c b/tests/testutilslxc.c new file mode 100644 index 0000000000000000000000000000000000000000..e6193afcf04644929c33e557ddd874087860e865 --- /dev/null +++ b/tests/testutilslxc.c @@ -0,0 +1,63 @@ +#include +#ifdef WITH_LXC +# include + +# include "testutilslxc.h" +# include "testutils.h" +# include "memory.h" +# include "domain_conf.h" + + +static int testLXCDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED) +{ + return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC; +} + + +virCapsPtr testLXCCapsInit(void) { + virCapsPtr caps; + virCapsGuestPtr guest; + + if ((caps = virCapabilitiesNew("x86_64", + 0, 0)) == NULL) + return NULL; + + caps->defaultConsoleTargetType = testLXCDefaultConsoleType; + + if ((guest = virCapabilitiesAddGuest(caps, "exe", "i686", 32, + "/usr/libexec/libvirt_lxc", NULL, + 0, NULL)) == NULL) + goto error; + + if (!virCapabilitiesAddGuestDomain(guest, "lxc", NULL, NULL, 0, NULL)) + goto error; + + + if ((guest = virCapabilitiesAddGuest(caps, "exe", "x86_64", 64, + "/usr/libexec/libvirt_lxc", NULL, + 0, NULL)) == NULL) + goto error; + + if (!virCapabilitiesAddGuestDomain(guest, "lxc", NULL, NULL, 0, NULL)) + goto error; + + + if (virTestGetDebug()) { + char *caps_str; + + caps_str = virCapabilitiesFormatXML(caps); + if (!caps_str) + goto error; + + fprintf(stderr, "LXC driver capabilities:\n%s", caps_str); + + VIR_FREE(caps_str); + } + + return caps; + +error: + virCapabilitiesFree(caps); + return NULL; +} +#endif diff --git a/tests/testutilslxc.h b/tests/testutilslxc.h new file mode 100644 index 0000000000000000000000000000000000000000..ee8056f1f595af1e9c0322a06d9eb11aa34b2186 --- /dev/null +++ b/tests/testutilslxc.h @@ -0,0 +1,4 @@ + +#include "capabilities.h" + +virCapsPtr testLXCCapsInit(void);