]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add support for setting init argv for LXC
authorDaniel P. Berrange <berrange@redhat.com>
Mon, 26 Mar 2012 17:09:31 +0000 (18:09 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 27 Mar 2012 14:52:25 +0000 (15:52 +0100)
Pass argv to the init binary of LXC, using a new <initarg> element.

* docs/formatdomain.html.in: Document <os> usage for containers
* docs/schemas/domaincommon.rng: Add <initarg> element
* src/conf/domain_conf.c, src/conf/domain_conf.h: parsing and
  formatting of <initarg>
* src/lxc/lxc_container.c: Setup LXC argv
* tests/Makefile.am, tests/lxcxml2xmldata/lxc-systemd.xml,
  tests/lxcxml2xmltest.c, tests/testutilslxc.c,
  tests/testutilslxc.h: Test parsing/formatting of LXC related
  XML parts

docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/lxc/lxc_container.c
tests/Makefile.am
tests/lxcxml2xmldata/lxc-systemd.xml [new file with mode: 0644]
tests/lxcxml2xmltest.c [new file with mode: 0644]
tests/testutilslxc.c [new file with mode: 0644]
tests/testutilslxc.h [new file with mode: 0644]

index faa5e462d16521da08859d1029a1ba46013ff487..863377ca857325b2ed72331cfdfbc65d82021d3b 100644 (file)
         installation media source / kickstart file</dd>
     </dl>
 
+    <h4><a name="eleemntsOSContainer">Container boot</a></h4>
+
+    <p>
+      When booting a domain using container based virtualization, instead
+      of a kernel / boot image, a path to the init binary is required, using
+      the <code>init</code> element. By default this will be launched with
+      no arguments. To specify the initial argv, use the <code>initarg</code>
+      element, repeated as many time as is required. The <code>cmdline</code>
+      element, if set will be used to provide an equivalent to <code>/proc/cmdline</code>
+      but will not effect init argv.
+    </p>
+
+    <pre>
+  &lt;os&gt;
+    &lt;type arch='x86_64'&gt;exe&lt;/type&gt;
+    &lt;init&gt;/bin/systemd&lt;/init&gt;
+    &lt;initarg&gt;--unit&lt;/initarg&gt;
+    &lt;initarg&gt;emergency.service&lt;/initarg&gt;
+  &lt;/os&gt;
+    </pre>
+
+
     <h3><a name="elementsSysinfo">SMBIOS System Information</a></h3>
 
     <p>
index 1f5232ef15a765ffde59142bbe3d762f901e3771..730f3d8e8ba339d19f24d13a95eb1f5793f3e58d 100644 (file)
             <ref name="absFilePath"/>
           </element>
         </optional>
+        <zeroOrMore>
+          <element name="initarg">
+            <text/>
+          </element>
+        </zeroOrMore>
       </interleave>
     </element>
   </define>
index e235c13581d19e31e041e5f712da8b04178ae9bb..ea558bbcef81bc2944e94566d34c2d3fd17442bc 100644 (file)
@@ -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 <initarg> 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, "    <quota>%lld</quota>\n",
                           def->cputune.quota);
     if (def->cputune.vcpupin) {
-        int i;
         for (i = 0; i < def->cputune.nvcpupin; i++) {
             virBufferAsprintf(buf, "    <vcpupin vcpu='%u' ",
                               def->cputune.vcpupin[i]->vcpuid);
@@ -12408,6 +12430,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
 
     virBufferEscapeString(buf, "    <init>%s</init>\n",
                           def->os.init);
+    for (i = 0 ; def->os.initargv && def->os.initargv[i] ; i++)
+        virBufferEscapeString(buf, "    <initarg>%s</initarg>\n",
+                              def->os.initargv[i]);
     virBufferEscapeString(buf, "    <loader>%s</loader>\n",
                           def->os.loader);
     virBufferEscapeString(buf, "    <kernel>%s</kernel>\n",
@@ -12462,7 +12487,6 @@ virDomainDefFormatInternal(virDomainDefPtr def,
     virBufferAddLit(buf, "  </os>\n");
 
     if (def->features) {
-        int i;
         virBufferAddLit(buf, "  <features>\n");
         for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
             if (def->features & (1 << i)) {
index 10030a494e0460665700ef0b60b1046186899c2d..3fcb02644c8e581677f02542d776dfb64c6a88a4 100644 (file)
@@ -1354,6 +1354,7 @@ struct _virDomainOSDef {
     int bootDevs[VIR_DOMAIN_BOOT_LAST];
     int bootmenu;
     char *init;
+    char **initargv;
     char *kernel;
     char *initrd;
     char *cmdline;
index bb64b606f73d13d6472f727768c69becf99c047f..0755b3cc5028bf7fefd6a65b11b655421ea83dcb 100644 (file)
@@ -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");
index 4755a3e6ea2ae431513d104230dd53ae8aa724db..4a0686ff4bf524e78d88478ea94f51a785ed34e5 100644 (file)
@@ -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 (file)
index 0000000..bf239c2
--- /dev/null
@@ -0,0 +1,30 @@
+<domain type='lxc'>
+  <name>demo</name>
+  <uuid>8369f1ac-7e46-e869-4ca5-759d51478066</uuid>
+  <memory unit='KiB'>500000</memory>
+  <currentMemory unit='KiB'>500000</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='x86_64'>exe</type>
+    <init>/bin/systemd</init>
+    <initarg>--unit</initarg>
+    <initarg>emergency.service</initarg>
+  </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='/root/container'/>
+      <target dir='/'/>
+    </filesystem>
+    <filesystem type='mount' accessmode='passthrough'>
+      <source dir='/home'/>
+      <target dir='/home'/>
+    </filesystem>
+    <console type='pty'>
+      <target type='lxc' port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git a/tests/lxcxml2xmltest.c b/tests/lxcxml2xmltest.c
new file mode 100644 (file)
index 0000000..558bd01
--- /dev/null
@@ -0,0 +1,141 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#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 (file)
index 0000000..e6193af
--- /dev/null
@@ -0,0 +1,63 @@
+#include <config.h>
+#ifdef WITH_LXC
+# include <stdlib.h>
+
+# 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 (file)
index 0000000..ee8056f
--- /dev/null
@@ -0,0 +1,4 @@
+
+#include "capabilities.h"
+
+virCapsPtr testLXCCapsInit(void);