[libvirt] [PATCH 1/6] Introduce new domain create APIs to pass pre-opened FDs to LXC

Daniel P. Berrange berrange at redhat.com
Fri Jul 12 15:38:27 UTC 2013


From: "Daniel P. Berrange" <berrange at redhat.com>

With container based virt, it is useful to be able to pass
pre-opened file descriptors to the container init process.
This allows for containers to be auto-activated from incoming
socket connections, passing the active socket into the container.

To do this, introduce a pair of new APIs, virDomainCreateXMLWithFiles
and virDomainCreateWithFiles, which accept an array of file
descriptors. For the LXC driver, UNIX file descriptor passing
will be used to send them to libvirtd, which will them pass
them down to libvirt_lxc, which will then pass them to the container
init process.

This will only be implemented for LXC right now, but the design
is generic enough it could work with other hypervisors, hence
I suggest adding this to libvirt.so, rather than libvirt-lxc.so

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 include/libvirt/libvirt.h.in          |  10 +++
 python/generator.py                   |   3 +
 python/libvirt-override-virConnect.py |  30 +++++++
 python/libvirt-override-virDomain.py  |  38 +++++++++
 python/libvirt-override.c             |  89 ++++++++++++++++++++
 src/driver.h                          |  13 +++
 src/libvirt.c                         | 154 ++++++++++++++++++++++++++++++++++
 src/libvirt_public.syms               |   6 ++
 8 files changed, 343 insertions(+)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index b87255a..150a231 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1575,6 +1575,11 @@ virConnectPtr           virDomainGetConnect     (virDomainPtr domain);
 virDomainPtr            virDomainCreateXML      (virConnectPtr conn,
                                                  const char *xmlDesc,
                                                  unsigned int flags);
+virDomainPtr            virDomainCreateXMLWithFiles(virConnectPtr conn,
+                                                    const char *xmlDesc,
+                                                    unsigned int nfiles,
+                                                    int *files,
+                                                    unsigned int flags);
 virDomainPtr            virDomainLookupByName   (virConnectPtr conn,
                                                  const char *name);
 virDomainPtr            virDomainLookupByID     (virConnectPtr conn,
@@ -2175,6 +2180,11 @@ int                     virDomainCreate         (virDomainPtr domain);
 int                     virDomainCreateWithFlags (virDomainPtr domain,
                                                   unsigned int flags);
 
+int                     virDomainCreateWithFiles (virDomainPtr domain,
+                                                  unsigned int nfiles,
+                                                  int *files,
+                                                  unsigned int flags);
+
 int                     virDomainGetAutostart   (virDomainPtr domain,
                                                  int *autostart);
 int                     virDomainSetAutostart   (virDomainPtr domain,
diff --git a/python/generator.py b/python/generator.py
index da642eb..427cebc 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -513,6 +513,9 @@ skip_function = (
     'virConnectUnregisterCloseCallback', # overriden in virConnect.py
     'virConnectRegisterCloseCallback', # overriden in virConnect.py
 
+    'virDomainCreateXMLWithFiles', # overriden in virConnect.py
+    'virDomainCreateWithFiles', # overriden in virDomain.py
+
     # 'Ref' functions have no use for bindings users.
     "virConnectRef",
     "virDomainRef",
diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py
index 5495b70..a0f579d 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -310,3 +310,33 @@
         if ret == -1:
             raise libvirtError ('virConnectRegisterCloseCallback() failed', conn=self)
         return ret
+
+    def createXMLWithFiles(self, xmlDesc, files, flags=0):
+        """Launch a new guest domain, based on an XML description similar
+        to the one returned by virDomainGetXMLDesc()
+        This function may require privileged access to the hypervisor.
+        The domain is not persistent, so its definition will disappear when it
+        is destroyed, or if the host is restarted (see virDomainDefineXML() to
+        define persistent domains).
+
+        @files provides an array of file descriptors which will be
+        made available to the 'init' process of the guest. The file
+        handles exposed to the guest will be renumbered to start
+        from 3 (ie immediately following stderr). This is only
+        supported for guests which use container based virtualization
+        technology.
+
+        If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
+        will be started, but its CPUs will remain paused. The CPUs
+        can later be manually started using virDomainResume.
+
+        If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+        domain will be automatically destroyed when the virConnectPtr
+        object is finally released. This will also happen if the
+        client application crashes / loses its connection to the
+        libvirtd daemon. Any domains marked for auto destroy will
+        block attempts at migration, save-to-file, or snapshots. """
+        ret = libvirtmod.virDomainCreateXMLWithFiles(self._o, xmlDesc, files, flags)
+        if ret is None:raise libvirtError('virDomainCreateXMLWithFiles() failed', conn=self)
+        __tmp = virDomain(self,_obj=ret)
+        return __tmp
diff --git a/python/libvirt-override-virDomain.py b/python/libvirt-override-virDomain.py
index 142b1d4..c96cc5e 100644
--- a/python/libvirt-override-virDomain.py
+++ b/python/libvirt-override-virDomain.py
@@ -9,3 +9,41 @@
             retlist.append(virDomainSnapshot(self, _obj=snapptr))
 
         return retlist
+
+
+    def createWithFiles(self, files, flags=0):
+        """Launch a defined domain. If the call succeeds the domain moves from the
+        defined to the running domains pools.
+
+        @files provides an array of file descriptors which will be
+        made available to the 'init' process of the guest. The file
+        handles exposed to the guest will be renumbered to start
+        from 3 (ie immediately following stderr). This is only
+        supported for guests which use container based virtualization
+        technology.
+
+        If the VIR_DOMAIN_START_PAUSED flag is set, or if the guest domain
+        has a managed save image that requested paused state (see
+        virDomainManagedSave()) the guest domain will be started, but its
+        CPUs will remain paused. The CPUs can later be manually started
+        using virDomainResume().  In all other cases, the guest domain will
+        be running.
+
+        If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+        domain will be automatically destroyed when the virConnectPtr
+        object is finally released. This will also happen if the
+        client application crashes / loses its connection to the
+        libvirtd daemon. Any domains marked for auto destroy will
+        block attempts at migration, save-to-file, or snapshots.
+
+        If the VIR_DOMAIN_START_BYPASS_CACHE flag is set, and there is a
+        managed save file for this domain (created by virDomainManagedSave()),
+        then libvirt will attempt to bypass the file system cache while restoring
+        the file, or fail if it cannot do so for the given system; this can allow
+        less pressure on file system cache, but also risks slowing loads from NFS.
+
+        If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save
+        file for this domain is discarded, and the domain boots from scratch. """
+        ret = libvirtmod.virDomainCreateWithFiles(self._o, files, flags)
+        if ret == -1: raise libvirtError ('virDomainCreateWithFiles() failed', dom=self)
+        return ret
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index e6c19a7..1023284 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -7001,6 +7001,93 @@ error:
 }
 
 
+static PyObject *
+libvirt_virDomainCreateWithFiles(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+    PyObject *py_retval = NULL;
+    int c_retval;
+    virDomainPtr domain;
+    PyObject *pyobj_domain;
+    PyObject *pyobj_files;
+    unsigned int flags;
+    unsigned int nfiles;
+    int *files = NULL;
+    size_t i;
+
+    if (!PyArg_ParseTuple(args, (char *)"OOi:virDomainCreateWithFiles",
+                          &pyobj_domain, &pyobj_files, &flags))
+        return NULL;
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    nfiles = PyList_Size(pyobj_files);
+
+    if (VIR_ALLOC_N_QUIET(files, nfiles) < 0)
+        return PyErr_NoMemory();
+
+    for (i = 0; i < nfiles; i++) {
+        PyObject *pyfd;
+        int fd;
+
+        pyfd = PyList_GetItem(pyobj_files, i);
+
+        if (libvirt_intUnwrap(pyfd, &fd) < 0)
+            goto cleanup;
+    }
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainCreateWithFiles(domain, nfiles, files, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+    py_retval = libvirt_intWrap((int) c_retval);
+
+cleanup:
+    VIR_FREE(files);
+    return py_retval;
+}
+
+
+static PyObject *
+libvirt_virDomainCreateXMLWithFiles(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+    PyObject *py_retval = NULL;
+    virDomainPtr c_retval;
+    virConnectPtr conn;
+    PyObject *pyobj_conn;
+    char * xmlDesc;
+    PyObject *pyobj_files;
+    unsigned int flags;
+    unsigned int nfiles;
+    int *files = NULL;
+    size_t i;
+
+    if (!PyArg_ParseTuple(args, (char *)"OzOi:virDomainCreateXMLWithFiles",
+                          &pyobj_conn, &xmlDesc, &pyobj_files, &flags))
+        return NULL;
+    conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn);
+
+    nfiles = PyList_Size(pyobj_files);
+
+    if (VIR_ALLOC_N_QUIET(files, nfiles) < 0)
+        return PyErr_NoMemory();
+
+    for (i = 0; i < nfiles; i++) {
+        PyObject *pyfd;
+        int fd;
+
+        pyfd = PyList_GetItem(pyobj_files, i);
+
+        if (libvirt_intUnwrap(pyfd, &fd) < 0)
+            goto cleanup;
+    }
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainCreateXMLWithFiles(conn, xmlDesc, nfiles, files, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+    py_retval = libvirt_virDomainPtrWrap((virDomainPtr) c_retval);
+
+cleanup:
+    VIR_FREE(files);
+    return py_retval;
+}
+
+
 /************************************************************************
  *									*
  *			The registration stuff				*
@@ -7126,6 +7213,8 @@ static PyMethodDef libvirtMethods[] = {
     {(char *) "virNodeGetMemoryParameters", libvirt_virNodeGetMemoryParameters, METH_VARARGS, NULL},
     {(char *) "virNodeSetMemoryParameters", libvirt_virNodeSetMemoryParameters, METH_VARARGS, NULL},
     {(char *) "virNodeGetCPUMap", libvirt_virNodeGetCPUMap, METH_VARARGS, NULL},
+    {(char *) "virDomainCreateXMLWithFiles", libvirt_virDomainCreateXMLWithFiles, METH_VARARGS, NULL},
+    {(char *) "virDomainCreateWithFiles", libvirt_virDomainCreateWithFiles, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}
 };
 
diff --git a/src/driver.h b/src/driver.h
index 31851cb..f4f5873 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -136,6 +136,12 @@ typedef virDomainPtr
 (*virDrvDomainCreateXML)(virConnectPtr conn,
                          const char *xmlDesc,
                          unsigned int flags);
+typedef virDomainPtr
+(*virDrvDomainCreateXMLWithFiles)(virConnectPtr conn,
+                                  const char *xmlDesc,
+                                  unsigned int nfiles,
+                                  int *files,
+                                  unsigned int flags);
 
 typedef virDomainPtr
 (*virDrvDomainLookupByID)(virConnectPtr conn,
@@ -334,6 +340,11 @@ typedef int
 typedef int
 (*virDrvDomainCreateWithFlags)(virDomainPtr dom,
                                unsigned int flags);
+typedef int
+(*virDrvDomainCreateWithFiles)(virDomainPtr dom,
+                               unsigned int nfiles,
+                               int *files,
+                               unsigned int flags);
 
 typedef virDomainPtr
 (*virDrvDomainDefineXML)(virConnectPtr conn,
@@ -1139,6 +1150,7 @@ struct _virDriver {
     virDrvConnectNumOfDomains connectNumOfDomains;
     virDrvConnectListAllDomains connectListAllDomains;
     virDrvDomainCreateXML domainCreateXML;
+    virDrvDomainCreateXMLWithFiles domainCreateXMLWithFiles;
     virDrvDomainLookupByID domainLookupByID;
     virDrvDomainLookupByUUID domainLookupByUUID;
     virDrvDomainLookupByName domainLookupByName;
@@ -1195,6 +1207,7 @@ struct _virDriver {
     virDrvConnectNumOfDefinedDomains connectNumOfDefinedDomains;
     virDrvDomainCreate domainCreate;
     virDrvDomainCreateWithFlags domainCreateWithFlags;
+    virDrvDomainCreateWithFiles domainCreateWithFiles;
     virDrvDomainDefineXML domainDefineXML;
     virDrvDomainUndefine domainUndefine;
     virDrvDomainUndefineFlags domainUndefineFlags;
diff --git a/src/libvirt.c b/src/libvirt.c
index 4dc91d7..5899f68 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -2004,6 +2004,79 @@ error:
 }
 
 /**
+ * virDomainCreateXMLWithFiles:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: string containing an XML description of the domain
+ * @nfiles: number of file descriptors passed
+ * @files: list of file descriptors passed
+ * @flags: bitwise-OR of supported virDomainCreateFlags
+ *
+ * Launch a new guest domain, based on an XML description similar
+ * to the one returned by virDomainGetXMLDesc()
+ * This function may require privileged access to the hypervisor.
+ * The domain is not persistent, so its definition will disappear when it
+ * is destroyed, or if the host is restarted (see virDomainDefineXML() to
+ * define persistent domains).
+ *
+ * @files provides an array of file descriptors which will be
+ * made available to the 'init' process of the guest. The file
+ * handles exposed to the guest will be renumbered to start
+ * from 3 (ie immediately following stderr). This is only
+ * supported for guests which use container based virtualization
+ * technology.
+ *
+ * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
+ * will be started, but its CPUs will remain paused. The CPUs
+ * can later be manually started using virDomainResume.
+ *
+ * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+ * domain will be automatically destroyed when the virConnectPtr
+ * object is finally released. This will also happen if the
+ * client application crashes / loses its connection to the
+ * libvirtd daemon. Any domains marked for auto destroy will
+ * block attempts at migration, save-to-file, or snapshots.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+virDomainCreateXMLWithFiles(virConnectPtr conn, const char *xmlDesc,
+                            unsigned int nfiles,
+                            int *files,
+                            unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, xmlDesc=%s, nfiles=%u, files=%p, flags=%x",
+              conn, xmlDesc, nfiles, files, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__);
+        virDispatchError(NULL);
+        return NULL;
+    }
+    virCheckNonNullArgGoto(xmlDesc, error);
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainCreateXMLWithFiles) {
+        virDomainPtr ret;
+        ret = conn->driver->domainCreateXMLWithFiles(conn, xmlDesc,
+                                                     nfiles, files,
+                                                     flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+/**
  * virDomainCreateLinux:
  * @conn: pointer to the hypervisor connection
  * @xmlDesc: string containing an XML description of the domain
@@ -9361,6 +9434,87 @@ error:
 }
 
 /**
+ * virDomainCreateWithFiles:
+ * @domain: pointer to a defined domain
+ * @nfiles: number of file descriptors passed
+ * @files: list of file descriptors passed
+ * @flags: bitwise-OR of supported virDomainCreateFlags
+ *
+ * Launch a defined domain. If the call succeeds the domain moves from the
+ * defined to the running domains pools.
+ *
+ * @files provides an array of file descriptors which will be
+ * made available to the 'init' process of the guest. The file
+ * handles exposed to the guest will be renumbered to start
+ * from 3 (ie immediately following stderr). This is only
+ * supported for guests which use container based virtualization
+ * technology.
+ *
+ * If the VIR_DOMAIN_START_PAUSED flag is set, or if the guest domain
+ * has a managed save image that requested paused state (see
+ * virDomainManagedSave()) the guest domain will be started, but its
+ * CPUs will remain paused. The CPUs can later be manually started
+ * using virDomainResume().  In all other cases, the guest domain will
+ * be running.
+ *
+ * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+ * domain will be automatically destroyed when the virConnectPtr
+ * object is finally released. This will also happen if the
+ * client application crashes / loses its connection to the
+ * libvirtd daemon. Any domains marked for auto destroy will
+ * block attempts at migration, save-to-file, or snapshots.
+ *
+ * If the VIR_DOMAIN_START_BYPASS_CACHE flag is set, and there is a
+ * managed save file for this domain (created by virDomainManagedSave()),
+ * then libvirt will attempt to bypass the file system cache while restoring
+ * the file, or fail if it cannot do so for the given system; this can allow
+ * less pressure on file system cache, but also risks slowing loads from NFS.
+ *
+ * If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save
+ * file for this domain is discarded, and the domain boots from scratch.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+virDomainCreateWithFiles(virDomainPtr domain, unsigned int nfiles,
+                         int *files, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "nfiles=%u, files=%p, flags=%x",
+                     nfiles, files, flags);
+
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+    conn = domain->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainCreateWithFiles) {
+        int ret;
+        ret = conn->driver->domainCreateWithFiles(domain,
+                                                  nfiles, files,
+                                                  flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+/**
  * virDomainGetAutostart:
  * @domain: a domain object
  * @autostart: the value returned
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 7c6edf6..20ac87f 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -627,4 +627,10 @@ LIBVIRT_1.1.0 {
         virDomainMigrateToURI3;
 } LIBVIRT_1.0.6;
 
+LIBVIRT_1.1.1 {
+    global:
+        virDomainCreateWithFiles;
+        virDomainCreateXMLWithFiles;
+} LIBVIRT_1.1.0;
+
 # .... define new API here using predicted next version number ....
-- 
1.8.1.4




More information about the libvir-list mailing list