2 * python-lxc: Python bindings for LXC
4 * (C) Copyright Canonical Ltd. 2012
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "structmember.h"
26 #include <lxc/lxccontainer.h>
32 struct lxc_container
*container
;
36 convert_tuple_to_char_pointer_array(PyObject
*argv
) {
37 int argc
= PyTuple_Size(argv
);
40 char **result
= (char**) malloc(sizeof(char*)*argc
+ 1);
42 for (i
= 0; i
< argc
; i
++) {
43 PyObject
*pyobj
= PyTuple_GetItem(argv
, i
);
47 if (!PyUnicode_Check(pyobj
)) {
48 PyErr_SetString(PyExc_ValueError
, "Expected a string");
52 pystr
= PyUnicode_AsUTF8String(pyobj
);
53 str
= PyBytes_AsString(pystr
);
54 memcpy((char *) &result
[i
], (char *) &str
, sizeof(str
));
63 Container_dealloc(Container
* self
)
65 Py_TYPE(self
)->tp_free((PyObject
*)self
);
69 Container_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
73 self
= (Container
*)type
->tp_alloc(type
, 0);
75 return (PyObject
*)self
;
79 Container_init(Container
*self
, PyObject
*args
, PyObject
*kwds
)
81 static char *kwlist
[] = {"name", "config_path", NULL
};
83 char *config_path
= NULL
;
85 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s|s", kwlist
,
89 self
->container
= lxc_container_new(name
, config_path
);
90 if (!self
->container
) {
91 fprintf(stderr
, "%d: error creating lxc_container %s\n", __LINE__
, name
);
98 // Container properties
100 Container_config_file_name(Container
*self
, PyObject
*args
, PyObject
*kwds
)
102 return PyUnicode_FromString(self
->container
->config_file_name(self
->container
));
106 Container_defined(Container
*self
, PyObject
*args
, PyObject
*kwds
)
108 if (self
->container
->is_defined(self
->container
)) {
116 Container_init_pid(Container
*self
, PyObject
*args
, PyObject
*kwds
)
118 return Py_BuildValue("i", self
->container
->init_pid(self
->container
));
122 Container_name(Container
*self
, PyObject
*args
, PyObject
*kwds
)
124 return PyUnicode_FromString(self
->container
->name
);
128 Container_running(Container
*self
, PyObject
*args
, PyObject
*kwds
)
130 if (self
->container
->is_running(self
->container
)) {
138 Container_state(Container
*self
, PyObject
*args
, PyObject
*kwds
)
140 return PyUnicode_FromString(self
->container
->state(self
->container
));
143 // Container Functions
145 Container_clear_config_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
147 static char *kwlist
[] = {"key", NULL
};
150 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|", kwlist
,
154 if (self
->container
->clear_config_item(self
->container
, key
)) {
162 Container_create(Container
*self
, PyObject
*args
, PyObject
*kwds
)
164 char* template_name
= NULL
;
165 char** create_args
= {NULL
};
166 PyObject
*vargs
= NULL
;
167 static char *kwlist
[] = {"template", "args", NULL
};
169 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|O", kwlist
,
170 &template_name
, &vargs
))
173 if (vargs
&& PyTuple_Check(vargs
)) {
174 create_args
= convert_tuple_to_char_pointer_array(vargs
);
180 if (self
->container
->create(self
->container
, template_name
, create_args
)) {
188 Container_destroy(Container
*self
, PyObject
*args
, PyObject
*kwds
)
190 if (self
->container
->destroy(self
->container
)) {
198 Container_freeze(Container
*self
, PyObject
*args
, PyObject
*kwds
)
200 if (self
->container
->freeze(self
->container
)) {
208 Container_get_cgroup_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
210 static char *kwlist
[] = {"key", NULL
};
214 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|", kwlist
,
218 len
= self
->container
->get_cgroup_item(self
->container
, key
, NULL
, 0);
224 char* value
= (char*) malloc(sizeof(char)*len
+ 1);
225 if (self
->container
->get_cgroup_item(self
->container
, key
, value
, len
+ 1) != len
) {
229 return PyUnicode_FromString(value
);
233 Container_get_config_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
235 static char *kwlist
[] = {"key", NULL
};
239 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|", kwlist
,
243 len
= self
->container
->get_config_item(self
->container
, key
, NULL
, 0);
249 char* value
= (char*) malloc(sizeof(char)*len
+ 1);
250 if (self
->container
->get_config_item(self
->container
, key
, value
, len
+ 1) != len
) {
254 return PyUnicode_FromString(value
);
258 Container_get_config_path(Container
*self
, PyObject
*args
, PyObject
*kwds
)
260 return PyUnicode_FromString(self
->container
->get_config_path(self
->container
));
264 Container_get_keys(Container
*self
, PyObject
*args
, PyObject
*kwds
)
266 static char *kwlist
[] = {"key", NULL
};
270 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|s", kwlist
,
274 len
= self
->container
->get_keys(self
->container
, key
, NULL
, 0);
280 char* value
= (char*) malloc(sizeof(char)*len
+ 1);
281 if (self
->container
->get_keys(self
->container
, key
, value
, len
+ 1) != len
) {
285 return PyUnicode_FromString(value
);
289 Container_load_config(Container
*self
, PyObject
*args
, PyObject
*kwds
)
291 static char *kwlist
[] = {"path", NULL
};
294 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|s", kwlist
,
298 if (self
->container
->load_config(self
->container
, path
)) {
306 Container_save_config(Container
*self
, PyObject
*args
, PyObject
*kwds
)
308 static char *kwlist
[] = {"path", NULL
};
311 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|s", kwlist
,
315 if (self
->container
->save_config(self
->container
, path
)) {
323 Container_set_cgroup_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
325 static char *kwlist
[] = {"key", "value", NULL
};
329 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "ss|", kwlist
,
333 if (self
->container
->set_cgroup_item(self
->container
, key
, value
)) {
341 Container_set_config_item(Container
*self
, PyObject
*args
, PyObject
*kwds
)
343 static char *kwlist
[] = {"key", "value", NULL
};
347 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "ss|", kwlist
,
351 if (self
->container
->set_config_item(self
->container
, key
, value
)) {
359 Container_set_config_path(Container
*self
, PyObject
*args
, PyObject
*kwds
)
361 static char *kwlist
[] = {"path", NULL
};
364 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|", kwlist
,
368 if (self
->container
->set_config_path(self
->container
, path
)) {
376 Container_shutdown(Container
*self
, PyObject
*args
, PyObject
*kwds
)
378 static char *kwlist
[] = {"timeout", NULL
};
381 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|i", kwlist
,
385 if (self
->container
->shutdown(self
->container
, timeout
)) {
393 Container_start(Container
*self
, PyObject
*args
, PyObject
*kwds
)
395 char** init_args
= {NULL
};
396 PyObject
*useinit
= NULL
, *vargs
= NULL
;
397 int init_useinit
= 0;
398 static char *kwlist
[] = {"useinit", "cmd", NULL
};
400 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "|OO", kwlist
,
404 if (useinit
&& useinit
== Py_True
) {
408 if (vargs
&& PyTuple_Check(vargs
)) {
409 init_args
= convert_tuple_to_char_pointer_array(vargs
);
415 self
->container
->want_daemonize(self
->container
);
417 if (self
->container
->start(self
->container
, init_useinit
, init_args
)) {
425 Container_stop(Container
*self
, PyObject
*args
, PyObject
*kwds
)
427 if (self
->container
->stop(self
->container
)) {
435 Container_unfreeze(Container
*self
, PyObject
*args
, PyObject
*kwds
)
437 if (self
->container
->unfreeze(self
->container
)) {
445 Container_wait(Container
*self
, PyObject
*args
, PyObject
*kwds
)
447 static char *kwlist
[] = {"state", "timeout", NULL
};
451 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "s|i", kwlist
,
455 if (self
->container
->wait(self
->container
, state
, timeout
)) {
462 static PyGetSetDef Container_getseters
[] = {
464 (getter
)Container_config_file_name
, 0,
465 "Path to the container configuration",
468 (getter
)Container_defined
, 0,
469 "Boolean indicating whether the container configuration exists",
472 (getter
)Container_init_pid
, 0,
473 "PID of the container's init process in the host's PID namespace",
476 (getter
)Container_name
, 0,
480 (getter
)Container_running
, 0,
481 "Boolean indicating whether the container is running or not",
484 (getter
)Container_state
, 0,
489 static PyMethodDef Container_methods
[] = {
490 {"clear_config_item", (PyCFunction
)Container_clear_config_item
, METH_VARARGS
| METH_KEYWORDS
,
491 "clear_config_item(key) -> boolean\n"
493 "Clear the current value of a config key."
495 {"create", (PyCFunction
)Container_create
, METH_VARARGS
| METH_KEYWORDS
,
496 "create(template, args = (,)) -> boolean\n"
498 "Create a new rootfs for the container, using the given template "
499 "and passing some optional arguments to it."
501 {"destroy", (PyCFunction
)Container_destroy
, METH_NOARGS
,
502 "destroy() -> boolean\n"
504 "Destroys the container."
506 {"freeze", (PyCFunction
)Container_freeze
, METH_NOARGS
,
507 "freeze() -> boolean\n"
509 "Freezes the container and returns its return code."
511 {"get_cgroup_item", (PyCFunction
)Container_get_cgroup_item
, METH_VARARGS
| METH_KEYWORDS
,
512 "get_cgroup_item(key) -> string\n"
514 "Get the current value of a cgroup entry."
516 {"get_config_item", (PyCFunction
)Container_get_config_item
, METH_VARARGS
| METH_KEYWORDS
,
517 "get_config_item(key) -> string\n"
519 "Get the current value of a config key."
521 {"get_config_path", (PyCFunction
)Container_get_config_path
, METH_NOARGS
,
522 "get_config_path() -> string\n"
524 "Return the LXC config path (where the containers are stored)."
526 {"get_keys", (PyCFunction
)Container_get_keys
, METH_VARARGS
| METH_KEYWORDS
,
527 "get_keys(key) -> string\n"
529 "Get a list of valid sub-keys for a key."
531 {"load_config", (PyCFunction
)Container_load_config
, METH_VARARGS
| METH_KEYWORDS
,
532 "load_config(path = DEFAULT) -> boolean\n"
534 "Read the container configuration from its default "
535 "location or from an alternative location if provided."
537 {"save_config", (PyCFunction
)Container_save_config
, METH_VARARGS
| METH_KEYWORDS
,
538 "save_config(path = DEFAULT) -> boolean\n"
540 "Save the container configuration to its default "
541 "location or to an alternative location if provided."
543 {"set_cgroup_item", (PyCFunction
)Container_set_cgroup_item
, METH_VARARGS
| METH_KEYWORDS
,
544 "set_cgroup_item(key, value) -> boolean\n"
546 "Set a cgroup entry to the provided value."
548 {"set_config_item", (PyCFunction
)Container_set_config_item
, METH_VARARGS
| METH_KEYWORDS
,
549 "set_config_item(key, value) -> boolean\n"
551 "Set a config key to the provided value."
553 {"set_config_path", (PyCFunction
)Container_set_config_path
, METH_VARARGS
| METH_KEYWORDS
,
554 "set_config_path(path) -> boolean\n"
556 "Set the LXC config path (where the containers are stored)."
558 {"shutdown", (PyCFunction
)Container_shutdown
, METH_VARARGS
| METH_KEYWORDS
,
559 "shutdown(timeout = -1) -> boolean\n"
561 "Sends SIGPWR to the container and wait for it to shutdown "
562 "unless timeout is set to a positive value, in which case "
563 "the container will be killed when the timeout is reached."
565 {"start", (PyCFunction
)Container_start
, METH_VARARGS
| METH_KEYWORDS
,
566 "start(useinit = False, cmd = (,)) -> boolean\n"
568 "Start the container, optionally using lxc-init and "
569 "an alternate init command, then returns its return code."
571 {"stop", (PyCFunction
)Container_stop
, METH_NOARGS
,
572 "stop() -> boolean\n"
574 "Stop the container and returns its return code."
576 {"unfreeze", (PyCFunction
)Container_unfreeze
, METH_NOARGS
,
577 "unfreeze() -> boolean\n"
579 "Unfreezes the container and returns its return code."
581 {"wait", (PyCFunction
)Container_wait
, METH_VARARGS
| METH_KEYWORDS
,
582 "wait(state, timeout = -1) -> boolean\n"
584 "Wait for the container to reach a given state or timeout."
586 {NULL
} /* Sentinel */
589 static PyTypeObject _lxc_ContainerType
= {
590 PyVarObject_HEAD_INIT(NULL
, 0)
591 "lxc.Container", /* tp_name */
592 sizeof(Container
), /* tp_basicsize */
594 (destructor
)Container_dealloc
, /* tp_dealloc */
600 0, /* tp_as_number */
601 0, /* tp_as_sequence */
602 0, /* tp_as_mapping */
608 0, /* tp_as_buffer */
610 Py_TPFLAGS_BASETYPE
, /* tp_flags */
611 "Container objects", /* tp_doc */
614 0, /* tp_richcompare */
615 0, /* tp_weaklistoffset */
618 Container_methods
, /* tp_methods */
620 Container_getseters
, /* tp_getset */
623 0, /* tp_descr_get */
624 0, /* tp_descr_set */
625 0, /* tp_dictoffset */
626 (initproc
)Container_init
, /* tp_init */
628 Container_new
, /* tp_new */
631 static PyModuleDef _lxcmodule
= {
632 PyModuleDef_HEAD_INIT
,
634 "Binding for liblxc in python",
636 NULL
, NULL
, NULL
, NULL
, NULL
644 if (PyType_Ready(&_lxc_ContainerType
) < 0)
647 m
= PyModule_Create(&_lxcmodule
);
651 Py_INCREF(&_lxc_ContainerType
);
652 PyModule_AddObject(m
, "Container", (PyObject
*)&_lxc_ContainerType
);