This is something I previously submitted as part of one of the LXC
patches, but I figure it makes sense on its own, since OpenVZ needs
this now too.
This adds two new XML elements to the domain XML format:
- An <init> block within <os> allowing specification of the path for
a binary to run when starting the container - aka 'init' by any other
name. First we also specify that all containers will use an OS
type of 'exe' - as in executable - the container equivalent of 'hvm'
<os>
<type>exe</type>
<init>/sbin/init</init>
</os>
- An <filesystem> element for specifying how the container's filesystem
is to be provided. This can actually be useful for full-machine virt
too such as KVM which have host filesystem pass-through. There are
various ways to configure it:
eg to use '/some/directory' as the root filesystem for a container
<filesystem type='mount'>
<source dir='/some/directory'/>
<target dir='/'/>
</filesystem>
eg to use a template called 'fedora9web' as the root filesystem for
a container
<filesystem type='template'>
<source name='fedora9web'/>
<target dir='/'/>
</filesystem>
eg to use a file containing a filesystem as the root filesystem
<filesystem type='file'>
<source file='/some/file.img'/>
<target dir='/'/>
</filesystem>
eg to use a disk partition or other block device (eg LVM) containing
a filesystem as the root filesystem
<filesystem type='block'>
<source dev='/dev/VolGroup00/Fedora9Web'/>
<target dir='/'/>
</filesystem>
If setting the root filesystem, the target path will be '/', some
container based virt allows the host OS root filesystem to be
used in the guest, and merely specify additive mounts at specific
locations,
eg to override just /home within a container
<filesystem type='mount'>
<source dir='/some/directory'/>
<target dir='/home'/>
</filesystem>
I believe this should satisfy all the OpenVZ, LXC and Linux-VServer
drivers' requirements around filesystems
Daniel
diff -r 5614da5fe9ef src/domain_conf.c
--- a/src/domain_conf.c Fri Jul 25 15:38:46 2008 +0100
+++ b/src/domain_conf.c Tue Jul 29 16:03:38 2008 +0100
@@ -86,6 +86,12 @@
"virtio",
"xen")
+VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
+ "mount",
+ "block",
+ "file",
+ "template")
+
VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
"user",
"ethernet",
@@ -234,6 +240,18 @@
VIR_FREE(def->driverType);
virDomainDiskDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainFSDefFree(virDomainFSDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->src);
+ VIR_FREE(def->dst);
+
+ virDomainFSDefFree(def->next);
VIR_FREE(def);
}
@@ -345,6 +363,7 @@
virDomainGraphicsDefFree(def->graphics);
virDomainInputDefFree(def->inputs);
virDomainDiskDefFree(def->disks);
+ virDomainFSDefFree(def->fss);
virDomainNetDefFree(def->nets);
virDomainChrDefFree(def->serials);
virDomainChrDefFree(def->parallels);
@@ -355,6 +374,7 @@
VIR_FREE(def->os.type);
VIR_FREE(def->os.arch);
VIR_FREE(def->os.machine);
+ VIR_FREE(def->os.init);
VIR_FREE(def->os.kernel);
VIR_FREE(def->os.initrd);
VIR_FREE(def->os.cmdline);
@@ -620,6 +640,89 @@
error:
virDomainDiskDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+/* Parse the XML definition for a disk
+ * @param node XML nodeset to parse for disk definition
+ */
+static virDomainFSDefPtr
+virDomainFSDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainFSDefPtr def;
+ xmlNodePtr cur;
+ char *type = NULL;
+ char *source = NULL;
+ char *target = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ if (type) {
+ if ((def->type = virDomainFSTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown filesystem type '%s'"),
type);
+ goto error;
+ }
+ } else {
+ def->type = VIR_DOMAIN_FS_TYPE_MOUNT;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((source == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+
+ if (def->type == VIR_DOMAIN_FS_TYPE_MOUNT)
+ source = virXMLPropString(cur, "dir");
+ else if (def->type == VIR_DOMAIN_FS_TYPE_FILE)
+ source = virXMLPropString(cur, "file");
+ else if (def->type == VIR_DOMAIN_FS_TYPE_BLOCK)
+ source = virXMLPropString(cur, "dev");
+ else if (def->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
+ source = virXMLPropString(cur, "name");
+ } else if ((target == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+ target = virXMLPropString(cur, "dir");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
+ def->readonly = 1;
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (source == NULL) {
+ virDomainReportError(conn, VIR_ERR_NO_SOURCE,
+ target ? "%s" : NULL, target);
+ goto error;
+ }
+
+ if (target == NULL) {
+ virDomainReportError(conn, VIR_ERR_NO_TARGET,
+ source ? "%s" : NULL, source);
+ goto error;
+ }
+
+ def->src = source;
+ source = NULL;
+ def->dst = target;
+ target = NULL;
+
+cleanup:
+ VIR_FREE(type);
+ VIR_FREE(target);
+ VIR_FREE(source);
+
+ return def;
+
+ error:
+ virDomainFSDefFree(def);
def = NULL;
goto cleanup;
}
@@ -1351,6 +1454,10 @@
dev->type = VIR_DOMAIN_DEVICE_DISK;
if (!(dev->data.disk = virDomainDiskDefParseXML(conn, node)))
goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "filesystem")) {
+ dev->type = VIR_DOMAIN_DEVICE_FS;
+ if (!(dev->data.fs = virDomainFSDefParseXML(conn, node)))
+ goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
dev->type = VIR_DOMAIN_DEVICE_NET;
if (!(dev->data.net = virDomainNetDefParseXML(conn, node)))
@@ -1560,7 +1667,21 @@
}
}
- if (!def->os.bootloader) {
+ /*
+ * Booting options for different OS types....
+ *
+ * - A bootloader (and optional kernel+initrd) (xen)
+ * - A kernel + initrd (xen)
+ * - A boot device (and optional kernel+initrd) (hvm)
+ * - An init script (exe)
+ */
+
+ if (STREQ(def->os.type, "exe")) {
+ def->os.init = virXPathString(conn, "string(./os/init[1])", ctxt);
+ }
+
+ if (STREQ(def->os.type, "xen") ||
+ STREQ(def->os.type, "hvm")) {
def->os.kernel = virXPathString(conn, "string(./os/kernel[1])",
ctxt);
def->os.initrd = virXPathString(conn, "string(./os/initrd[1])",
ctxt);
def->os.cmdline = virXPathString(conn, "string(./os/cmdline[1])",
ctxt);
@@ -1610,12 +1731,9 @@
def->os.type,
def->os.arch,
type);
- if (!emulator) {
- virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("unsupported guest type"));
- goto error;
- }
- if (!(def->emulator = strdup(emulator))) {
+
+ if (emulator &&
+ !(def->emulator = strdup(emulator))) {
virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
goto error;
}
@@ -1648,6 +1766,23 @@
ptr = ptr->next;
}
}
+ }
+ VIR_FREE(nodes);
+
+ /* analysis of the filesystems */
+ if ((n = virXPathNodeSet(conn, "./devices/filesystem", ctxt, &nodes))
< 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract filesystem
devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainFSDefPtr fs = virDomainFSDefParseXML(conn,
+ nodes[i]);
+ if (!fs)
+ goto error;
+
+ fs->next = def->fss;
+ def->fss = fs;
}
VIR_FREE(nodes);
@@ -2202,6 +2337,57 @@
}
static int
+virDomainFSDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainFSDefPtr def)
+{
+ const char *type = virDomainFSTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected filesystem type %d"),
def->type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf,
+ " <filesystem type='%s'>\n",
+ type);
+
+ if (def->src) {
+ switch (def->type) {
+ case VIR_DOMAIN_FS_TYPE_MOUNT:
+ virBufferEscapeString(buf, " <source
dir='%s'/>\n",
+ def->src);
+ break;
+
+ case VIR_DOMAIN_FS_TYPE_BLOCK:
+ virBufferEscapeString(buf, " <source
dev='%s'/>\n",
+ def->src);
+ break;
+
+ case VIR_DOMAIN_FS_TYPE_FILE:
+ virBufferEscapeString(buf, " <source
file='%s'/>\n",
+ def->src);
+ break;
+
+ case VIR_DOMAIN_FS_TYPE_TEMPLATE:
+ virBufferEscapeString(buf, " <source
name='%s'/>\n",
+ def->src);
+ }
+ }
+
+ virBufferVSprintf(buf, " <target dir='%s'/>\n",
+ def->dst);
+
+ if (def->readonly)
+ virBufferAddLit(buf, " <readonly/>\n");
+
+ virBufferAddLit(buf, " </filesystem>\n");
+
+ return 0;
+}
+
+static int
virDomainNetDefFormat(virConnectPtr conn,
virBufferPtr buf,
virDomainNetDefPtr def)
@@ -2479,6 +2665,7 @@
unsigned char *uuid;
char uuidstr[VIR_UUID_STRING_BUFLEN];
virDomainDiskDefPtr disk;
+ virDomainFSDefPtr fs;
virDomainNetDefPtr net;
virDomainSoundDefPtr sound;
virDomainInputDefPtr input;
@@ -2548,6 +2735,9 @@
else
virBufferVSprintf(&buf, ">%s</type>\n", def->os.type);
+ if (def->os.init)
+ virBufferEscapeString(&buf, " <init>%s</init>\n",
+ def->os.init);
if (def->os.loader)
virBufferEscapeString(&buf, "
<loader>%s</loader>\n",
def->os.loader);
@@ -2621,6 +2811,13 @@
if (virDomainDiskDefFormat(conn, &buf, disk) < 0)
goto cleanup;
disk = disk->next;
+ }
+
+ fs = def->fss;
+ while (fs) {
+ if (virDomainFSDefFormat(conn, &buf, fs) < 0)
+ goto cleanup;
+ fs = fs->next;
}
net = def->nets;
diff -r 5614da5fe9ef src/domain_conf.h
--- a/src/domain_conf.h Fri Jul 25 15:38:46 2008 +0100
+++ b/src/domain_conf.h Tue Jul 29 16:03:38 2008 +0100
@@ -91,6 +91,28 @@
unsigned int shared : 1;
virDomainDiskDefPtr next;
+};
+
+
+/* Two types of disk backends */
+enum virDomainFSType {
+ VIR_DOMAIN_FS_TYPE_MOUNT, /* Better named 'bind' */
+ VIR_DOMAIN_FS_TYPE_BLOCK,
+ VIR_DOMAIN_FS_TYPE_FILE,
+ VIR_DOMAIN_FS_TYPE_TEMPLATE,
+
+ VIR_DOMAIN_FS_TYPE_LAST
+};
+
+typedef struct _virDomainFSDef virDomainFSDef;
+typedef virDomainFSDef *virDomainFSDefPtr;
+struct _virDomainFSDef {
+ int type;
+ char *src;
+ char *dst;
+ unsigned int readonly : 1;
+
+ virDomainFSDefPtr next;
};
@@ -262,6 +284,7 @@
/* Flags for the 'type' field in next struct */
enum virDomainDeviceType {
VIR_DOMAIN_DEVICE_DISK,
+ VIR_DOMAIN_DEVICE_FS,
VIR_DOMAIN_DEVICE_NET,
VIR_DOMAIN_DEVICE_INPUT,
VIR_DOMAIN_DEVICE_SOUND,
@@ -273,6 +296,7 @@
int type;
union {
virDomainDiskDefPtr disk;
+ virDomainFSDefPtr fs;
virDomainNetDefPtr net;
virDomainInputDefPtr input;
virDomainSoundDefPtr sound;
@@ -318,6 +342,7 @@
char *machine;
int nBootDevs;
int bootDevs[VIR_DOMAIN_BOOT_LAST];
+ char *init;
char *kernel;
char *initrd;
char *cmdline;
@@ -357,6 +382,7 @@
virDomainGraphicsDefPtr graphics;
virDomainDiskDefPtr disks;
+ virDomainFSDefPtr fss;
virDomainNetDefPtr nets;
virDomainInputDefPtr inputs;
virDomainSoundDefPtr sounds;
@@ -411,6 +437,7 @@
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
void virDomainInputDefFree(virDomainInputDefPtr def);
void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainFSDefFree(virDomainFSDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
@@ -481,6 +508,7 @@
VIR_ENUM_DECL(virDomainDisk)
VIR_ENUM_DECL(virDomainDiskDevice)
VIR_ENUM_DECL(virDomainDiskBus)
+VIR_ENUM_DECL(virDomainFS)
VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainSoundModel)
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|