mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
Add support for setting init argv for LXC
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
This commit is contained in:
parent
eb8f31c16b
commit
c91cff255f
@ -250,6 +250,28 @@
|
|||||||
installation media source / kickstart file</dd>
|
installation media source / kickstart file</dd>
|
||||||
</dl>
|
</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>
|
||||||
|
<os>
|
||||||
|
<type arch='x86_64'>exe</type>
|
||||||
|
<init>/bin/systemd</init>
|
||||||
|
<initarg>--unit</initarg>
|
||||||
|
<initarg>emergency.service</initarg>
|
||||||
|
</os>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
<h3><a name="elementsSysinfo">SMBIOS System Information</a></h3>
|
<h3><a name="elementsSysinfo">SMBIOS System Information</a></h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -378,6 +378,11 @@
|
|||||||
<ref name="absFilePath"/>
|
<ref name="absFilePath"/>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<zeroOrMore>
|
||||||
|
<element name="initarg">
|
||||||
|
<text/>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
</interleave>
|
</interleave>
|
||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
@ -1559,6 +1559,9 @@ void virDomainDefFree(virDomainDefPtr def)
|
|||||||
VIR_FREE(def->os.arch);
|
VIR_FREE(def->os.arch);
|
||||||
VIR_FREE(def->os.machine);
|
VIR_FREE(def->os.machine);
|
||||||
VIR_FREE(def->os.init);
|
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.kernel);
|
||||||
VIR_FREE(def->os.initrd);
|
VIR_FREE(def->os.initrd);
|
||||||
VIR_FREE(def->os.cmdline);
|
VIR_FREE(def->os.cmdline);
|
||||||
@ -8188,6 +8191,25 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
|
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") ||
|
if (STREQ(def->os.type, "xen") ||
|
||||||
@ -12171,6 +12193,7 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||||
const char *type = NULL;
|
const char *type = NULL;
|
||||||
int n, allones = 1;
|
int n, allones = 1;
|
||||||
|
int i;
|
||||||
bool blkio = false;
|
bool blkio = false;
|
||||||
|
|
||||||
virCheckFlags(DUMPXML_FLAGS |
|
virCheckFlags(DUMPXML_FLAGS |
|
||||||
@ -12332,7 +12355,6 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
virBufferAsprintf(buf, " <quota>%lld</quota>\n",
|
virBufferAsprintf(buf, " <quota>%lld</quota>\n",
|
||||||
def->cputune.quota);
|
def->cputune.quota);
|
||||||
if (def->cputune.vcpupin) {
|
if (def->cputune.vcpupin) {
|
||||||
int i;
|
|
||||||
for (i = 0; i < def->cputune.nvcpupin; i++) {
|
for (i = 0; i < def->cputune.nvcpupin; i++) {
|
||||||
virBufferAsprintf(buf, " <vcpupin vcpu='%u' ",
|
virBufferAsprintf(buf, " <vcpupin vcpu='%u' ",
|
||||||
def->cputune.vcpupin[i]->vcpuid);
|
def->cputune.vcpupin[i]->vcpuid);
|
||||||
@ -12408,6 +12430,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
|
|
||||||
virBufferEscapeString(buf, " <init>%s</init>\n",
|
virBufferEscapeString(buf, " <init>%s</init>\n",
|
||||||
def->os.init);
|
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",
|
virBufferEscapeString(buf, " <loader>%s</loader>\n",
|
||||||
def->os.loader);
|
def->os.loader);
|
||||||
virBufferEscapeString(buf, " <kernel>%s</kernel>\n",
|
virBufferEscapeString(buf, " <kernel>%s</kernel>\n",
|
||||||
@ -12462,7 +12487,6 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
virBufferAddLit(buf, " </os>\n");
|
virBufferAddLit(buf, " </os>\n");
|
||||||
|
|
||||||
if (def->features) {
|
if (def->features) {
|
||||||
int i;
|
|
||||||
virBufferAddLit(buf, " <features>\n");
|
virBufferAddLit(buf, " <features>\n");
|
||||||
for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
|
for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
|
||||||
if (def->features & (1 << i)) {
|
if (def->features & (1 << i)) {
|
||||||
|
@ -1354,6 +1354,7 @@ struct _virDomainOSDef {
|
|||||||
int bootDevs[VIR_DOMAIN_BOOT_LAST];
|
int bootDevs[VIR_DOMAIN_BOOT_LAST];
|
||||||
int bootmenu;
|
int bootmenu;
|
||||||
char *init;
|
char *init;
|
||||||
|
char **initargv;
|
||||||
char *kernel;
|
char *kernel;
|
||||||
char *initrd;
|
char *initrd;
|
||||||
char *cmdline;
|
char *cmdline;
|
||||||
|
@ -122,6 +122,9 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef)
|
|||||||
|
|
||||||
cmd = virCommandNew(vmDef->os.init);
|
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, "PATH=/bin:/sbin");
|
||||||
virCommandAddEnvString(cmd, "TERM=linux");
|
virCommandAddEnvString(cmd, "TERM=linux");
|
||||||
virCommandAddEnvString(cmd, "container=lxc-libvirt");
|
virCommandAddEnvString(cmd, "container=lxc-libvirt");
|
||||||
|
@ -60,6 +60,7 @@ EXTRA_DIST = \
|
|||||||
domainsnapshotxml2xmlin \
|
domainsnapshotxml2xmlin \
|
||||||
domainsnapshotxml2xmlout \
|
domainsnapshotxml2xmlout \
|
||||||
interfaceschemadata \
|
interfaceschemadata \
|
||||||
|
lxcxml2xmldata \
|
||||||
networkschematest \
|
networkschematest \
|
||||||
networkxml2xmlin \
|
networkxml2xmlin \
|
||||||
networkxml2xmlout \
|
networkxml2xmlout \
|
||||||
@ -115,6 +116,10 @@ check_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \
|
|||||||
qemumonitortest
|
qemumonitortest
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WITH_LXC
|
||||||
|
check_PROGRAMS += lxcxml2xmltest
|
||||||
|
endif
|
||||||
|
|
||||||
if WITH_OPENVZ
|
if WITH_OPENVZ
|
||||||
check_PROGRAMS += openvzutilstest
|
check_PROGRAMS += openvzutilstest
|
||||||
endif
|
endif
|
||||||
@ -245,6 +250,10 @@ TESTS += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest qemuargv2xmltest \
|
|||||||
qemumonitortest
|
qemumonitortest
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WITH_LXC
|
||||||
|
TESTS += lxcxml2xmltest
|
||||||
|
endif
|
||||||
|
|
||||||
if WITH_OPENVZ
|
if WITH_OPENVZ
|
||||||
TESTS += openvzutilstest
|
TESTS += openvzutilstest
|
||||||
endif
|
endif
|
||||||
@ -383,6 +392,18 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c \
|
|||||||
qemumonitortest.c testutilsqemu.c testutilsqemu.h
|
qemumonitortest.c testutilsqemu.c testutilsqemu.h
|
||||||
endif
|
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
|
if WITH_OPENVZ
|
||||||
openvzutilstest_SOURCES = \
|
openvzutilstest_SOURCES = \
|
||||||
openvzutilstest.c \
|
openvzutilstest.c \
|
||||||
|
30
tests/lxcxml2xmldata/lxc-systemd.xml
Normal file
30
tests/lxcxml2xmldata/lxc-systemd.xml
Normal file
@ -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>
|
141
tests/lxcxml2xmltest.c
Normal file
141
tests/lxcxml2xmltest.c
Normal file
@ -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 */
|
63
tests/testutilslxc.c
Normal file
63
tests/testutilslxc.c
Normal file
@ -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
|
4
tests/testutilslxc.h
Normal file
4
tests/testutilslxc.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
#include "capabilities.h"
|
||||||
|
|
||||||
|
virCapsPtr testLXCCapsInit(void);
|
Loading…
Reference in New Issue
Block a user