lxc.c revision 4027875db1d25dba48712327afa0073c014f1930
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * python-lxc: Python bindings for LXC
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * (C) Copyright Canonical Ltd. 2012-2013
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * Stéphane Graber <stgraber@ubuntu.com>
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * This library is free software; you can redistribute it and/or
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * modify it under the terms of the GNU Lesser General Public
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * License as published by the Free Software Foundation; either
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * version 2.1 of the License, or (at your option) any later version.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * This library is distributed in the hope that it will be useful,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * but WITHOUT ANY WARRANTY; without even the implied warranty of
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * Lesser General Public License for more details.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * You should have received a copy of the GNU Lesser General Public
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * License along with this library; if not, write to the Free Software
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Helper functions */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherconvert_tuple_to_char_pointer_array(PyObject *argv) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* not a list or tuple */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_SetString(PyExc_TypeError, "Expected list or tuple.");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher result = (char**) calloc(argc + 1, sizeof(char*));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < argc; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyObject *pyobj = PySequence_Fast_GET_ITEM(argv, i);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_SetString(PyExc_ValueError, "Expected a string");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Maybe it wasn't UTF-8 encoded. An exception is already set. */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Maybe pystr wasn't a valid object. An exception is already set.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* We must make a copy of str, because it points into internal memory
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * which we do not own. Assume it's NULL terminated, otherwise we'd
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * have to use PyUnicode_AsUTF8AndSize() and be explicit about copying
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Do not decref pyobj since we stole a reference by using
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * PyTuple_GET_ITEM().
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* We can only iterate up to but not including i because malloc() does not
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * initialize its memory. Thus if we got here, i points to the index
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * after the last strdup'd entry in result.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (j = 0; j < i; j++)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic int lxc_attach_python_exec(void* _payload)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* This function is the first one to be called after attaching to a
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * container. As lxc_attach() calls fork() PyOS_AfterFork should be called
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * in the new process if the Python interpreter will continue to be used.
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher struct lxc_attach_python_payload *payload =
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher (struct lxc_attach_python_payload *)_payload;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyObject *result = PyObject_CallFunctionObjArgs(payload->fn,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic void lxc_attach_free_options(lxc_attach_options_t *options);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherstatic lxc_attach_options_t *lxc_attach_parse_options(PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher static char *kwlist[] = {"attach_flags", "namespaces", "personality",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher "initial_cwd", "uid", "gid", "env_policy",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher "extra_env_vars", "extra_keep_env", "stdin",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher lxc_attach_options_t default_options = LXC_ATTACH_OPTIONS_DEFAULT;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher lxc_attach_options_t *options = malloc(sizeof(*options));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher memcpy(options, &default_options, sizeof(*options));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* we need some dummy variables because we can't be sure
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher * the data types match completely */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* we need a dummy tuple */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher parse_result = PyArg_ParseTupleAndKeywords(dummy, kwds, "|iilO&lliOOOOO",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* immediately get rid of the dummy tuple */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* duplicate the string, so we don't depend on some random Python object */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options->initial_cwd = strndup(PyBytes_AsString(initial_cwd_obj),
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* do the type conversion from the types that match the parse string */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (temp_uid != -1) options->uid = (uid_t)temp_uid;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (temp_gid != -1) options->gid = (gid_t)temp_gid;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options->env_policy = (lxc_attach_env_policy_t)temp_env_policy;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher convert_tuple_to_char_pointer_array(extra_env_vars_obj);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher convert_tuple_to_char_pointer_array(extra_keep_env_obj);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options->stdin_fd = PyObject_AsFileDescriptor(stdin_obj);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options->stdout_fd = PyObject_AsFileDescriptor(stdout_obj);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher options->stderr_fd = PyObject_AsFileDescriptor(stderr_obj);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallaghervoid lxc_attach_free_options(lxc_attach_options_t *options)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; options->extra_env_vars[i]; i++)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; options->extra_keep_env[i]; i++)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Module functions */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherLXC_arch_to_personality(PyObject *self, PyObject *arg)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_SetString(PyExc_ValueError, "Expected a string");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_SetString(PyExc_KeyError, "Failed to lookup architecture.");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return rv == -1 ? NULL : PyLong_FromLong(rv);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherLXC_attach_run_command(PyObject *self, PyObject *arg)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!PyArg_ParseTuple(arg, "sO", (const char**)&cmd.program, &args_obj))
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher cmd.argv = convert_tuple_to_char_pointer_array(args_obj);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_Format(PyExc_TypeError, "Second part of tuple passed to "
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher "attach_run_command must be a list.");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherLXC_attach_run_shell(PyObject *self, PyObject *arg)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherLXC_get_global_config_item(PyObject *self, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherLXC_get_version(PyObject *self, PyObject *args)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return PyUnicode_FromString(lxc_get_version());
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherLXC_list_containers(PyObject *self, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher static char *kwlist[] = {"active", "defined", "config_path", NULL};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOs", kwlist,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* We default to listing everything */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (py_list_active && py_list_active != Py_True) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (py_list_defined && py_list_defined != Py_True) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Call the right API function based on filters */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (list_active == 1 && list_defined == 1)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher list_count = list_all_containers(config_path, &names, NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher list_count = list_active_containers(config_path, &names, NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher list_count = list_defined_containers(config_path, &names, NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Handle failure */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyErr_SetString(PyExc_ValueError, "failure to list containers");
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher /* Generate the tuple */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher for (i = 0; i < list_count; i++) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher PyTuple_SET_ITEM(list, i, PyUnicode_FromString(names[i]));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Base type and functions for Container */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallaghertypedef struct {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_init(Container *self, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher static char *kwlist[] = {"name", "config_path", NULL};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&", kwlist,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher config_path = PyBytes_AS_STRING(fs_config_path);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher self->container = lxc_container_new(name, config_path);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher fprintf(stderr, "%d: error creating container %s\n", __LINE__, name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher self = (Container *)type->tp_alloc(type, 0);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Container properties */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_config_file_name(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher self->container->config_file_name(self->container));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_controllable(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (self->container->may_control(self->container)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_defined(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (self->container->is_defined(self->container)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_init_pid(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return PyLong_FromLong(self->container->init_pid(self->container));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_name(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return PyUnicode_FromString(self->container->name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_running(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (self->container->is_running(self->container)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_state(Container *self, void *closure)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher return PyUnicode_FromString(self->container->state(self->container));
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher/* Container Functions */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_attach_interface(Container *self, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher static char *kwlist[] = {"src_ifname", "dst_ifname", NULL};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&", kwlist,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher src_name = PyBytes_AS_STRING(py_src_name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher dst_name = PyBytes_AS_STRING(py_dst_name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (self->container->attach_interface(self->container, src_name, dst_name)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_detach_interface(Container *self, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist,
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (self->container->detach_interface(self->container, ifname, NULL)) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen GallagherContainer_add_device_node(Container *self, PyObject *args, PyObject *kwds)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher static char *kwlist[] = {"src_path", "dest_path", NULL};
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (! PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&", kwlist,
dst_path)) {
static PyObject *
long ret;
return NULL;
return NULL;
if (!options)
return NULL;
if (ret < 0)
goto out;
if (wait) {
out:
static PyObject *
static PyObject *
static PyObject *
static PyObject *
&key))
return NULL;
static PyObject *
int flags = 0;
unsigned long newsize = 0;
&newname,
&py_hookargs))
return NULL;
if (py_hookargs) {
if (!hookargs) {
return NULL;
return NULL;
if (hookargs) {
static PyObject *
&escape))
return NULL;
static PyObject *
return NULL;
&masterfd) < 0) {
return NULL;
static PyObject *
int flags = 0;
return NULL;
if (vargs) {
if (!create_args) {
return NULL;
return NULL;
if (vargs) {
return retval;
static PyObject *
static PyObject *
static PyObject *
int len = 0;
char* value;
&key))
return NULL;
if (len < 0) {
return NULL;
return PyErr_NoMemory();
return NULL;
return ret;
static PyObject *
int len = 0;
char* value;
&key))
return NULL;
if (len < 0) {
return NULL;
if (len == 0) {
return PyErr_NoMemory();
return NULL;
return ret;
static PyObject *
return PyUnicode_FromString(
static PyObject *
int len = 0;
char* value;
&key))
return NULL;
if (len < 0) {
return NULL;
return PyErr_NoMemory();
return NULL;
return ret;
static PyObject *
if (!interfaces)
return PyTuple_New(0);
while (interfaces[i])
if (!ret)
return NULL;
while (interfaces[i]) {
if (!unicode) {
while (interfaces[i]) {
return ret;
static PyObject *
int scope = 0;
return NULL;
if (!ips)
return PyTuple_New(0);
while (ips[i])
if (!ret)
return NULL;
while (ips[i]) {
if (!unicode) {
while (ips[i]) {
return ret;
static PyObject *
&key))
return NULL;
if (!value)
return ret;
static PyObject *
return NULL;
static PyObject *
static PyObject *
&new_name))
return NULL;
static PyObject *
return NULL;
dst_path)) {
static PyObject *
return NULL;
static PyObject *
return NULL;
static PyObject *
return NULL;
static PyObject *
&path))
return NULL;
static PyObject *
&timeout))
return NULL;
static PyObject *
int retval = 0;
int ret = 0;
return NULL;
if (retval < 0) {
return NULL;
static PyObject *
&name))
return NULL;
static PyObject *
int snap_count = 0;
if (snap_count < 0) {
return NULL;
for (i = 0; i < snap_count; i++) {
return list;
static PyObject *
return NULL;
static PyObject *
int init_useinit = 0, i = 0;
&vargs))
return NULL;
if (!init_args) {
return NULL;
if (vargs) {
return retval;
static PyObject *
static PyObject *
static PyObject *
return NULL;
/* Function/Properties list */
NULL},
NULL},
NULL},
NULL},
NULL},
NULL},
NULL},
PyInit__lxc(void)
PyObject* m;
PyObject* d;
return NULL;
if (m == NULL)
return NULL;
d = PyModule_GetDict(m);
#define PYLXC_EXPORT_CONST(c) \