2 * python-lxc: Python bindings for LXC
4 * (C) Copyright Canonical Ltd. 2012-2013
7 * Stéphane Graber <stgraber@ubuntu.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "structmember.h"
26 #include <lxc/lxccontainer.h>
27 #include <lxc/utils.h>
28 #include <lxc/namespace.h>
29 #include <lxc/confile.h>
35 struct lxc_container
*container
;
39 convert_tuple_to_char_pointer_array(PyObject
*argv
) {
43 /* not a list or tuple */
44 if (!PyList_Check(argv
) && !PyTuple_Check(argv
)) {
45 PyErr_SetString(PyExc_TypeError
, "Expected list or tuple.");
49 argc
= PySequence_Fast_GET_SIZE(argv
);
51 char **result
= (char**) calloc(argc
+ 1, sizeof(char*));
54 PyErr_SetNone(PyExc_MemoryError
);
58 for (i
= 0; i
< argc
; i
++) {
59 PyObject
*pyobj
= PySequence_Fast_GET_ITEM(argv
, i
);
60 assert(pyobj
!= NULL
);
63 PyObject
*pystr
= NULL
;
65 if (!PyUnicode_Check(pyobj
)) {
66 PyErr_SetString(PyExc_ValueError
, "Expected a string");
70 pystr
= PyUnicode_AsUTF8String(pyobj
);
72 /* Maybe it wasn't UTF-8 encoded. An exception is already set. */
76 str
= PyBytes_AsString(pystr
);
78 /* Maybe pystr wasn't a valid object. An exception is already set.
84 /* We must make a copy of str, because it points into internal memory
85 * which we do not own. Assume it's NULL terminated, otherwise we'd
86 * have to use PyUnicode_AsUTF8AndSize() and be explicit about copying
89 result
[i
] = strdup(str
);
91 /* Do not decref pyobj since we stole a reference by using
95 if (result
[i
] == NULL
) {
96 PyErr_SetNone(PyExc_MemoryError
);
105 /* We can only iterate up to but not including i because malloc() does not
106 * initialize its memory. Thus if we got here, i points to the index
107 * after the last strdup'd entry in result.
109 for (j
= 0; j
< i
; j
++)
116 Container_dealloc(Container
* self
)
118 lxc_container_put(self
->container
);
119 Py_TYPE(self
)->tp_free((PyObject
*)self
);
123 Container_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
127 self
= (Container
*)type
->tp_alloc(type
, 0);
129 return (PyObject
*)self
;
133 Container_init(Container
*self
, PyObject
*args
, PyObject
*kwds
)
135 static char *kwlist
[] = {"name", "config_path", NULL
};
137 PyObject
*fs_config_path
= NULL
;
138 char *config_path
= NULL
;
140 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s|O&", kwlist
,
142 PyUnicode_FSConverter
, &fs_config_path
))
145 if (fs_config_path
!= NULL
) {
146 config_path
= PyBytes_AS_STRING(fs_config_path
);
147 assert(config_path
!= NULL
);
150 self
->container
= lxc_container_new(name
, config_path
);
151 if (!self
->container
) {
152 Py_XDECREF(fs_config_path
);
153 fprintf(stderr
, "%d: error creating container %s\n", __LINE__
, name
);
157 Py_XDECREF(fs_config_path
);
162 LXC_get_default_config_path(PyObject
*self
, PyObject
*args
)
164 return PyUnicode_FromString(lxc_get_default_config_path());
168 LXC_get_version(PyObject
*self
, PyObject
*args
)
170 return PyUnicode_FromString(lxc_get_version());
173 // Container properties
175 Container_config_file_name(Container
*self
, void *closure
)
177 return PyUnicode_FromString(
178 self
->container
->config_file_name(self
->container
));
182 Container_defined(Container
*self
, void *closure
)
184 if (self
->container
->is_defined(self
->container
)) {
192 Container_init_pid(Container
*self
, void *closure
)
194 return PyLong_FromLong(self
->container
->init_pid(self
->container
));
198 Container_name(Container
*self
, void *closure
)
200 return PyUnicode_FromString(self
->container
->name
);
204 Container_running(Container
*self
, void *closure
)
206 if (self
->container
->is_running(self
->container
)) {
214 Container_state(Container
*self
, void *closure
)
216 return PyUnicode_FromString(self
->container
->state(self
->container
));
219 // Container Functions
221 Container_clear_config_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
223 static char *kwlist
[] = {"key", NULL
};
226 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s", kwlist
,
230 if (self
->container
->clear_config_item(self
->container
, key
)) {
238 Container_create(Container
*self
, PyObject
*args
, PyObject
*kwds
)
240 char* template_name
= NULL
;
241 char** create_args
= {NULL
};
242 PyObject
*retval
= NULL
, *vargs
= NULL
;
244 static char *kwlist
[] = {"template", "args", NULL
};
246 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|O", kwlist
,
247 &template_name
, &vargs
))
251 if (PyTuple_Check(vargs
)) {
252 create_args
= convert_tuple_to_char_pointer_array(vargs
);
258 PyErr_SetString(PyExc_ValueError
, "args needs to be a tuple");
263 if (self
->container
->create(self
->container
, template_name
, NULL
, NULL
, 0, create_args
))
269 /* We cannot have gotten here unless vargs was given and create_args
270 * was successfully allocated.
272 for (i
= 0; i
< PyTuple_GET_SIZE(vargs
); i
++)
273 free(create_args
[i
]);
282 Container_destroy(Container
*self
, PyObject
*args
, PyObject
*kwds
)
284 if (self
->container
->destroy(self
->container
)) {
292 Container_freeze(Container
*self
, PyObject
*args
, PyObject
*kwds
)
294 if (self
->container
->freeze(self
->container
)) {
302 Container_get_cgroup_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
304 static char *kwlist
[] = {"key", NULL
};
307 PyObject
*ret
= NULL
;
309 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s", kwlist
,
313 len
= self
->container
->get_cgroup_item(self
->container
, key
, NULL
, 0);
316 PyErr_SetString(PyExc_KeyError
, "Invalid cgroup entry");
320 char* value
= (char*) malloc(sizeof(char)*len
+ 1);
322 return PyErr_NoMemory();
324 if (self
->container
->get_cgroup_item(self
->container
,
325 key
, value
, len
+ 1) != len
) {
326 PyErr_SetString(PyExc_ValueError
, "Unable to read config value");
331 ret
= PyUnicode_FromString(value
);
337 Container_get_config_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
339 static char *kwlist
[] = {"key", NULL
};
342 PyObject
*ret
= NULL
;
344 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|", kwlist
,
348 len
= self
->container
->get_config_item(self
->container
, key
, NULL
, 0);
351 PyErr_SetString(PyExc_KeyError
, "Invalid configuration key");
355 char* value
= (char*) malloc(sizeof(char)*len
+ 1);
357 return PyErr_NoMemory();
359 if (self
->container
->get_config_item(self
->container
,
360 key
, value
, len
+ 1) != len
) {
361 PyErr_SetString(PyExc_ValueError
, "Unable to read config value");
366 ret
= PyUnicode_FromString(value
);
372 Container_get_config_path(Container
*self
, PyObject
*args
, PyObject
*kwds
)
374 return PyUnicode_FromString(
375 self
->container
->get_config_path(self
->container
));
379 Container_get_keys(Container
*self
, PyObject
*args
, PyObject
*kwds
)
381 static char *kwlist
[] = {"key", NULL
};
384 PyObject
*ret
= NULL
;
386 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|s", kwlist
,
390 len
= self
->container
->get_keys(self
->container
, key
, NULL
, 0);
393 PyErr_SetString(PyExc_KeyError
, "Invalid configuration key");
397 char* value
= (char*) malloc(sizeof(char)*len
+ 1);
399 return PyErr_NoMemory();
401 if (self
->container
->get_keys(self
->container
,
402 key
, value
, len
+ 1) != len
) {
403 PyErr_SetString(PyExc_ValueError
, "Unable to read config keys");
408 ret
= PyUnicode_FromString(value
);
414 Container_get_ips(Container
*self
, PyObject
*args
, PyObject
*kwds
)
416 static char *kwlist
[] = {"interface", "family", "scope", NULL
};
417 char* interface
= NULL
;
426 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|ssi", kwlist
,
427 &interface
, &family
, &scope
))
431 ips
= self
->container
->get_ips(self
->container
, interface
, family
, scope
);
433 return PyTuple_New(0);
435 /* Count the entries */
439 /* Create the new tuple */
440 ret
= PyTuple_New(i
);
444 /* Add the entries to the tuple and free the memory */
447 PyObject
*unicode
= PyUnicode_FromString(ips
[i
]);
453 PyTuple_SET_ITEM(ret
, i
, unicode
);
457 /* Free the list of IPs */
469 Container_load_config(Container
*self
, PyObject
*args
, PyObject
*kwds
)
471 static char *kwlist
[] = {"path", NULL
};
472 PyObject
*fs_path
= NULL
;
475 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|O&", kwlist
,
476 PyUnicode_FSConverter
, &fs_path
))
479 if (fs_path
!= NULL
) {
480 path
= PyBytes_AS_STRING(fs_path
);
481 assert(path
!= NULL
);
484 if (self
->container
->load_config(self
->container
, path
)) {
494 Container_save_config(Container
*self
, PyObject
*args
, PyObject
*kwds
)
496 static char *kwlist
[] = {"path", NULL
};
497 PyObject
*fs_path
= NULL
;
500 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|O&", kwlist
,
501 PyUnicode_FSConverter
, &fs_path
))
504 if (fs_path
!= NULL
) {
505 path
= PyBytes_AS_STRING(fs_path
);
506 assert(path
!= NULL
);
509 if (self
->container
->save_config(self
->container
, path
)) {
519 Container_set_cgroup_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
521 static char *kwlist
[] = {"key", "value", NULL
};
525 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "ss", kwlist
,
529 if (self
->container
->set_cgroup_item(self
->container
, key
, value
)) {
537 Container_set_config_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
539 static char *kwlist
[] = {"key", "value", NULL
};
543 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "ss", kwlist
,
547 if (self
->container
->set_config_item(self
->container
, key
, value
)) {
555 Container_set_config_path(Container
*self
, PyObject
*args
, PyObject
*kwds
)
557 static char *kwlist
[] = {"path", NULL
};
560 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s", kwlist
,
564 if (self
->container
->set_config_path(self
->container
, path
)) {
572 Container_shutdown(Container
*self
, PyObject
*args
, PyObject
*kwds
)
574 static char *kwlist
[] = {"timeout", NULL
};
577 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|i", kwlist
,
581 if (self
->container
->shutdown(self
->container
, timeout
)) {
589 Container_start(Container
*self
, PyObject
*args
, PyObject
*kwds
)
591 char** init_args
= {NULL
};
592 PyObject
*useinit
= NULL
, *retval
= NULL
, *vargs
= NULL
;
593 int init_useinit
= 0, i
= 0;
594 static char *kwlist
[] = {"useinit", "cmd", NULL
};
596 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|OO", kwlist
,
600 if (useinit
&& useinit
== Py_True
) {
604 if (vargs
&& PyTuple_Check(vargs
)) {
605 init_args
= convert_tuple_to_char_pointer_array(vargs
);
611 self
->container
->want_daemonize(self
->container
);
613 if (self
->container
->start(self
->container
, init_useinit
, init_args
))
619 /* We cannot have gotten here unless vargs was given and create_args
620 * was successfully allocated.
622 for (i
= 0; i
< PyTuple_GET_SIZE(vargs
); i
++)
632 Container_stop(Container
*self
, PyObject
*args
, PyObject
*kwds
)
634 if (self
->container
->stop(self
->container
)) {
642 Container_unfreeze(Container
*self
, PyObject
*args
, PyObject
*kwds
)
644 if (self
->container
->unfreeze(self
->container
)) {
652 Container_console(Container
*self
, PyObject
*args
, PyObject
*kwds
)
654 static char *kwlist
[] = {"ttynum", "stdinfd", "stdoutfd", "stderrfd", "escape", NULL
};
655 int ttynum
= -1, stdinfd
= 0, stdoutfd
= 1, stderrfd
= 2, escape
= 1;
657 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|iiiii", kwlist
,
658 &ttynum
, &stdinfd
, &stdoutfd
, &stderrfd
,
662 if (self
->container
->console(self
->container
, ttynum
,
663 stdinfd
, stdoutfd
, stderrfd
, escape
) == 0) {
670 Container_console_getfd(Container
*self
, PyObject
*args
, PyObject
*kwds
)
672 static char *kwlist
[] = {"ttynum", NULL
};
673 int ttynum
= -1, masterfd
;
675 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|i", kwlist
, &ttynum
))
678 if (self
->container
->console_getfd(self
->container
, &ttynum
, &masterfd
) < 0) {
679 PyErr_SetString(PyExc_ValueError
, "Unable to allocate tty");
682 return PyLong_FromLong(masterfd
);
686 Container_wait(Container
*self
, PyObject
*args
, PyObject
*kwds
)
688 static char *kwlist
[] = {"state", "timeout", NULL
};
692 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|i", kwlist
,
696 if (self
->container
->wait(self
->container
, state
, timeout
)) {
703 struct lxc_attach_python_payload
{
708 static int lxc_attach_python_exec(void* _payload
)
710 struct lxc_attach_python_payload
*payload
= (struct lxc_attach_python_payload
*)_payload
;
711 PyObject
*result
= PyObject_CallFunctionObjArgs(payload
->fn
, payload
->arg
, NULL
);
717 if (PyLong_Check(result
))
718 return (int)PyLong_AsLong(result
);
723 static void lxc_attach_free_options(lxc_attach_options_t
*options
);
725 static lxc_attach_options_t
*lxc_attach_parse_options(PyObject
*kwds
)
727 static char *kwlist
[] = {"attach_flags", "namespaces", "personality", "initial_cwd", "uid", "gid", "env_policy", "extra_env_vars", "extra_keep_env", "stdin", "stdout", "stderr", NULL
};
728 long temp_uid
, temp_gid
;
730 PyObject
*extra_env_vars_obj
= NULL
;
731 PyObject
*extra_keep_env_obj
= NULL
;
732 PyObject
*stdin_obj
= NULL
;
733 PyObject
*stdout_obj
= NULL
;
734 PyObject
*stderr_obj
= NULL
;
735 PyObject
*initial_cwd_obj
= NULL
;
739 lxc_attach_options_t default_options
= LXC_ATTACH_OPTIONS_DEFAULT
;
740 lxc_attach_options_t
*options
= malloc(sizeof(*options
));
743 PyErr_SetNone(PyExc_MemoryError
);
746 memcpy(options
, &default_options
, sizeof(*options
));
748 /* we need some dummy variables because we can't be sure
749 * the data types match completely */
752 temp_env_policy
= options
->env_policy
;
754 /* we need a dummy tuple */
755 dummy
= PyTuple_New(0);
757 parse_result
= PyArg_ParseTupleAndKeywords(dummy
, kwds
, "|iilO&lliOOOOO", kwlist
,
758 &options
->attach_flags
, &options
->namespaces
, &options
->personality
,
759 PyUnicode_FSConverter
, &initial_cwd_obj
, &temp_uid
, &temp_gid
,
760 &temp_env_policy
, &extra_env_vars_obj
, &extra_keep_env_obj
,
761 &stdin_obj
, &stdout_obj
, &stderr_obj
);
763 /* immediately get rid of the dummy tuple */
767 lxc_attach_free_options(options
);
771 /* duplicate the string, so we don't depend on some random Python object */
772 if (initial_cwd_obj
!= NULL
) {
773 options
->initial_cwd
= strndup(PyBytes_AsString(initial_cwd_obj
), PyBytes_Size(initial_cwd_obj
));
774 Py_DECREF(initial_cwd_obj
);
777 /* do the type conversion from the types that match the parse string */
778 if (temp_uid
!= -1) options
->uid
= (uid_t
)temp_uid
;
779 if (temp_gid
!= -1) options
->gid
= (gid_t
)temp_gid
;
780 options
->env_policy
= (lxc_attach_env_policy_t
)temp_env_policy
;
782 if (extra_env_vars_obj
)
783 options
->extra_env_vars
= convert_tuple_to_char_pointer_array(extra_env_vars_obj
);
784 if (extra_keep_env_obj
)
785 options
->extra_keep_env
= convert_tuple_to_char_pointer_array(extra_keep_env_obj
);
787 options
->stdin_fd
= PyObject_AsFileDescriptor(stdin_obj
);
788 if (options
->stdin_fd
< 0) {
789 lxc_attach_free_options(options
);
794 options
->stdout_fd
= PyObject_AsFileDescriptor(stdout_obj
);
795 if (options
->stdout_fd
< 0) {
796 lxc_attach_free_options(options
);
801 options
->stderr_fd
= PyObject_AsFileDescriptor(stderr_obj
);
802 if (options
->stderr_fd
< 0) {
803 lxc_attach_free_options(options
);
811 void lxc_attach_free_options(lxc_attach_options_t
*options
)
816 if (options
->initial_cwd
)
817 free(options
->initial_cwd
);
818 if (options
->extra_env_vars
) {
819 for (i
= 0; options
->extra_env_vars
[i
]; i
++)
820 free(options
->extra_env_vars
[i
]);
821 free(options
->extra_env_vars
);
823 if (options
->extra_keep_env
) {
824 for (i
= 0; options
->extra_keep_env
[i
]; i
++)
825 free(options
->extra_keep_env
[i
]);
826 free(options
->extra_keep_env
);
832 Container_attach_and_possibly_wait(Container
*self
, PyObject
*args
, PyObject
*kwds
, int wait
)
834 struct lxc_attach_python_payload payload
= { NULL
, NULL
};
835 lxc_attach_options_t
*options
= NULL
;
839 if (!PyArg_ParseTuple(args
, "O|O", &payload
.fn
, &payload
.arg
))
841 if (!PyCallable_Check(payload
.fn
)) {
842 PyErr_Format(PyExc_TypeError
, "attach: object not callable");
846 options
= lxc_attach_parse_options(kwds
);
850 ret
= self
->container
->attach(self
->container
, lxc_attach_python_exec
, &payload
, options
, &pid
);
855 ret
= lxc_wait_for_pid_status(pid
);
856 /* handle case where attach fails */
857 if (WIFEXITED(ret
) && WEXITSTATUS(ret
) == 255)
864 lxc_attach_free_options(options
);
865 return PyLong_FromLong(ret
);
869 Container_attach(Container
*self
, PyObject
*args
, PyObject
*kwds
)
871 return Container_attach_and_possibly_wait(self
, args
, kwds
, 0);
875 Container_attach_wait(Container
*self
, PyObject
*args
, PyObject
*kwds
)
877 return Container_attach_and_possibly_wait(self
, args
, kwds
, 1);
881 LXC_attach_run_shell(PyObject
*self
, PyObject
*arg
)
885 rv
= lxc_attach_run_shell(NULL
);
887 return PyLong_FromLong(rv
);
891 LXC_arch_to_personality(PyObject
*self
, PyObject
*arg
)
897 if (!PyUnicode_Check(arg
)) {
898 PyErr_SetString(PyExc_ValueError
, "Expected a string");
902 pystr
= PyUnicode_AsUTF8String(arg
);
906 str
= PyBytes_AsString(pystr
);
910 rv
= lxc_config_parse_arch(str
);
912 PyErr_SetString(PyExc_KeyError
, "Failed to lookup architecture.");
916 return rv
== -1 ? NULL
: PyLong_FromLong(rv
);
920 LXC_attach_run_command(PyObject
*self
, PyObject
*arg
)
922 PyObject
*args_obj
= NULL
;
924 lxc_attach_command_t cmd
= {
929 if (!PyArg_ParseTuple(arg
, "sO", (const char**)&cmd
.program
, &args_obj
))
931 if (args_obj
&& PyList_Check(args_obj
)) {
932 cmd
.argv
= convert_tuple_to_char_pointer_array(args_obj
);
934 PyErr_Format(PyExc_TypeError
, "Second part of tuple passed to attach_run_command must be a list.");
941 rv
= lxc_attach_run_command(&cmd
);
943 for (i
= 0; cmd
.argv
[i
]; i
++)
947 return PyLong_FromLong(rv
);
950 static PyGetSetDef Container_getseters
[] = {
952 (getter
)Container_config_file_name
, NULL
,
953 "Path to the container configuration",
956 (getter
)Container_defined
, NULL
,
957 "Boolean indicating whether the container configuration exists",
960 (getter
)Container_init_pid
, NULL
,
961 "PID of the container's init process in the host's PID namespace",
964 (getter
)Container_name
, NULL
,
968 (getter
)Container_running
, NULL
,
969 "Boolean indicating whether the container is running or not",
972 (getter
)Container_state
, NULL
,
975 {NULL
, NULL
, NULL
, NULL
, NULL
}
978 static PyMethodDef Container_methods
[] = {
979 {"clear_config_item", (PyCFunction
)Container_clear_config_item
,
980 METH_VARARGS
|METH_KEYWORDS
,
981 "clear_config_item(key) -> boolean\n"
983 "Clear the current value of a config key."
985 {"create", (PyCFunction
)Container_create
,
986 METH_VARARGS
|METH_KEYWORDS
,
987 "create(template, args = (,)) -> boolean\n"
989 "Create a new rootfs for the container, using the given template "
990 "and passing some optional arguments to it."
992 {"destroy", (PyCFunction
)Container_destroy
,
994 "destroy() -> boolean\n"
996 "Destroys the container."
998 {"freeze", (PyCFunction
)Container_freeze
,
1000 "freeze() -> boolean\n"
1002 "Freezes the container and returns its return code."
1004 {"get_cgroup_item", (PyCFunction
)Container_get_cgroup_item
,
1005 METH_VARARGS
|METH_KEYWORDS
,
1006 "get_cgroup_item(key) -> string\n"
1008 "Get the current value of a cgroup entry."
1010 {"get_config_item", (PyCFunction
)Container_get_config_item
,
1011 METH_VARARGS
|METH_KEYWORDS
,
1012 "get_config_item(key) -> string\n"
1014 "Get the current value of a config key."
1016 {"get_config_path", (PyCFunction
)Container_get_config_path
,
1018 "get_config_path() -> string\n"
1020 "Return the LXC config path (where the containers are stored)."
1022 {"get_keys", (PyCFunction
)Container_get_keys
,
1023 METH_VARARGS
|METH_KEYWORDS
,
1024 "get_keys(key) -> string\n"
1026 "Get a list of valid sub-keys for a key."
1028 {"get_ips", (PyCFunction
)Container_get_ips
,
1029 METH_VARARGS
|METH_KEYWORDS
,
1030 "get_ips(interface, family, scope) -> tuple\n"
1032 "Get a tuple of IPs for the container."
1034 {"load_config", (PyCFunction
)Container_load_config
,
1035 METH_VARARGS
|METH_KEYWORDS
,
1036 "load_config(path = DEFAULT) -> boolean\n"
1038 "Read the container configuration from its default "
1039 "location or from an alternative location if provided."
1041 {"save_config", (PyCFunction
)Container_save_config
,
1042 METH_VARARGS
|METH_KEYWORDS
,
1043 "save_config(path = DEFAULT) -> boolean\n"
1045 "Save the container configuration to its default "
1046 "location or to an alternative location if provided."
1048 {"set_cgroup_item", (PyCFunction
)Container_set_cgroup_item
,
1049 METH_VARARGS
|METH_KEYWORDS
,
1050 "set_cgroup_item(key, value) -> boolean\n"
1052 "Set a cgroup entry to the provided value."
1054 {"set_config_item", (PyCFunction
)Container_set_config_item
,
1055 METH_VARARGS
|METH_KEYWORDS
,
1056 "set_config_item(key, value) -> boolean\n"
1058 "Set a config key to the provided value."
1060 {"set_config_path", (PyCFunction
)Container_set_config_path
,
1061 METH_VARARGS
|METH_KEYWORDS
,
1062 "set_config_path(path) -> boolean\n"
1064 "Set the LXC config path (where the containers are stored)."
1066 {"shutdown", (PyCFunction
)Container_shutdown
,
1067 METH_VARARGS
|METH_KEYWORDS
,
1068 "shutdown(timeout = -1) -> boolean\n"
1070 "Sends SIGPWR to the container and wait for it to shutdown "
1071 "unless timeout is set to a positive value, in which case "
1072 "the container will be killed when the timeout is reached."
1074 {"start", (PyCFunction
)Container_start
,
1075 METH_VARARGS
|METH_KEYWORDS
,
1076 "start(useinit = False, cmd = (,)) -> boolean\n"
1078 "Start the container, optionally using lxc-init and "
1079 "an alternate init command, then returns its return code."
1081 {"stop", (PyCFunction
)Container_stop
,
1083 "stop() -> boolean\n"
1085 "Stop the container and returns its return code."
1087 {"unfreeze", (PyCFunction
)Container_unfreeze
,
1089 "unfreeze() -> boolean\n"
1091 "Unfreezes the container and returns its return code."
1093 {"wait", (PyCFunction
)Container_wait
,
1094 METH_VARARGS
|METH_KEYWORDS
,
1095 "wait(state, timeout = -1) -> boolean\n"
1097 "Wait for the container to reach a given state or timeout."
1099 {"console", (PyCFunction
)Container_console
,
1100 METH_VARARGS
|METH_KEYWORDS
,
1101 "console(ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 0) -> boolean\n"
1103 "Attach to container's console."
1105 {"console_getfd", (PyCFunction
)Container_console_getfd
,
1106 METH_VARARGS
|METH_KEYWORDS
,
1107 "console(ttynum = -1) -> boolean\n"
1109 "Attach to container's console."
1111 {"attach", (PyCFunction
)Container_attach
,
1112 METH_VARARGS
|METH_KEYWORDS
,
1113 "attach(run, payload) -> int\n"
1115 "Attach to the container. Returns the pid of the attached process."
1117 {"attach_wait", (PyCFunction
)Container_attach_wait
,
1118 METH_VARARGS
|METH_KEYWORDS
,
1119 "attach(run, payload) -> int\n"
1121 "Attach to the container. Returns the exit code of the process."
1123 {NULL
, NULL
, 0, NULL
}
1126 static PyTypeObject _lxc_ContainerType
= {
1127 PyVarObject_HEAD_INIT(NULL
, 0)
1128 "lxc.Container", /* tp_name */
1129 sizeof(Container
), /* tp_basicsize */
1130 0, /* tp_itemsize */
1131 (destructor
)Container_dealloc
, /* tp_dealloc */
1135 0, /* tp_reserved */
1137 0, /* tp_as_number */
1138 0, /* tp_as_sequence */
1139 0, /* tp_as_mapping */
1143 0, /* tp_getattro */
1144 0, /* tp_setattro */
1145 0, /* tp_as_buffer */
1146 Py_TPFLAGS_DEFAULT
|
1147 Py_TPFLAGS_BASETYPE
, /* tp_flags */
1148 "Container objects", /* tp_doc */
1149 0, /* tp_traverse */
1151 0, /* tp_richcompare */
1152 0, /* tp_weaklistoffset */
1154 0, /* tp_iternext */
1155 Container_methods
, /* tp_methods */
1157 Container_getseters
, /* tp_getset */
1160 0, /* tp_descr_get */
1161 0, /* tp_descr_set */
1162 0, /* tp_dictoffset */
1163 (initproc
)Container_init
, /* tp_init */
1165 Container_new
, /* tp_new */
1168 static PyMethodDef LXC_methods
[] = {
1169 {"attach_run_shell", (PyCFunction
)LXC_attach_run_shell
, METH_O
,
1170 "Starts up a shell when attaching, to use as the run parameter for attach or attach_wait"},
1171 {"attach_run_command", (PyCFunction
)LXC_attach_run_command
, METH_O
,
1172 "Runs a command when attaching, to use as the run parameter for attach or attach_wait"},
1173 {"arch_to_personality", (PyCFunction
)LXC_arch_to_personality
, METH_O
,
1174 "Returns the process personality of the corresponding architecture"},
1175 {"get_default_config_path", (PyCFunction
)LXC_get_default_config_path
, METH_NOARGS
,
1176 "Returns the current LXC config path"},
1177 {"get_version", (PyCFunction
)LXC_get_version
, METH_NOARGS
,
1178 "Returns the current LXC library version"},
1179 {NULL
, NULL
, 0, NULL
}
1182 static PyModuleDef _lxcmodule
= {
1183 PyModuleDef_HEAD_INIT
,
1185 "Binding for liblxc in python",
1196 if (PyType_Ready(&_lxc_ContainerType
) < 0)
1199 m
= PyModule_Create(&_lxcmodule
);
1203 Py_INCREF(&_lxc_ContainerType
);
1204 PyModule_AddObject(m
, "Container", (PyObject
*)&_lxc_ContainerType
);
1207 d
= PyModule_GetDict(m
);
1209 #define PYLXC_EXPORT_CONST(c) PyDict_SetItemString(d, #c, PyLong_FromLong(c))
1211 /* environment variable handling */
1212 PYLXC_EXPORT_CONST(LXC_ATTACH_KEEP_ENV
);
1213 PYLXC_EXPORT_CONST(LXC_ATTACH_CLEAR_ENV
);
1215 /* attach options */
1216 PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP
);
1217 PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES
);
1218 PYLXC_EXPORT_CONST(LXC_ATTACH_SET_PERSONALITY
);
1219 PYLXC_EXPORT_CONST(LXC_ATTACH_APPARMOR
);
1220 PYLXC_EXPORT_CONST(LXC_ATTACH_REMOUNT_PROC_SYS
);
1221 PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT
);
1223 /* namespace flags (no other python lib exports this) */
1224 PYLXC_EXPORT_CONST(CLONE_NEWUTS
);
1225 PYLXC_EXPORT_CONST(CLONE_NEWIPC
);
1226 PYLXC_EXPORT_CONST(CLONE_NEWUSER
);
1227 PYLXC_EXPORT_CONST(CLONE_NEWPID
);
1228 PYLXC_EXPORT_CONST(CLONE_NEWNET
);
1229 PYLXC_EXPORT_CONST(CLONE_NEWNS
);
1231 #undef PYLXC_EXPORT_CONST
1237 * kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;