]> git.proxmox.com Git - mirror_lxc.git/blame - src/python-lxc/lxc.c
python: Add binding for {get|set}_cgroup_item
[mirror_lxc.git] / src / python-lxc / lxc.c
CommitLineData
be2e4e54
SG
1/*
2 * python-lxc: Python bindings for LXC
3 *
4 * (C) Copyright Canonical Ltd. 2012
5 *
6 * Authors:
7 * Stéphane Graber <stgraber@ubuntu.com>
8 *
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.
13 *
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.
18 *
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
22 */
23
24#include <Python.h>
25#include "structmember.h"
26#include <lxc/lxccontainer.h>
27#include <stdio.h>
28#include <sys/wait.h>
29
30typedef struct {
31 PyObject_HEAD
32 struct lxc_container *container;
33} Container;
34
35char**
36convert_tuple_to_char_pointer_array(PyObject *argv) {
37 int argc = PyTuple_Size(argv);
38 int i;
39
40 char **result = (char**) malloc(sizeof(char*)*argc + 1);
41
42 for (i = 0; i < argc; i++) {
43 PyObject *pyobj = PyTuple_GetItem(argv, i);
44
45 char *str = NULL;
46 PyObject *pystr;
47 if (!PyUnicode_Check(pyobj)) {
48 PyErr_SetString(PyExc_ValueError, "Expected a string");
49 return NULL;
50 }
51
52 pystr = PyUnicode_AsUTF8String(pyobj);
53 str = PyBytes_AsString(pystr);
54 memcpy((char *) &result[i], (char *) &str, sizeof(str));
55 }
56
57 result[argc] = NULL;
58
59 return result;
60}
61
be2e4e54
SG
62static void
63Container_dealloc(Container* self)
64{
65 Py_TYPE(self)->tp_free((PyObject*)self);
66}
67
68static PyObject *
69Container_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
70{
71 Container *self;
72
73 self = (Container *)type->tp_alloc(type, 0);
74
75 return (PyObject *)self;
76}
77
78static int
79Container_init(Container *self, PyObject *args, PyObject *kwds)
80{
81 static char *kwlist[] = {"name", NULL};
82 char *name = NULL;
83
84 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
85 &name))
86 return -1;
87
88 self->container = lxc_container_new(name);
89 if (!self->container) {
90 fprintf(stderr, "%d: error creating lxc_container %s\n", __LINE__, name);
91 return -1;
92 }
93
94 return 0;
95}
96
97// Container properties
98static PyObject *
99Container_config_file_name(Container *self, PyObject *args, PyObject *kwds)
100{
101 return PyUnicode_FromString(self->container->config_file_name(self->container));
102}
103
104static PyObject *
105Container_defined(Container *self, PyObject *args, PyObject *kwds)
106{
107 if (self->container->is_defined(self->container)) {
108 Py_RETURN_TRUE;
109 }
110
111 Py_RETURN_FALSE;
112}
113
114static PyObject *
115Container_init_pid(Container *self, PyObject *args, PyObject *kwds)
116{
117 return Py_BuildValue("i", self->container->init_pid(self->container));
118}
119
120static PyObject *
121Container_name(Container *self, PyObject *args, PyObject *kwds)
122{
123 return PyUnicode_FromString(self->container->name);
124}
125
126static PyObject *
127Container_running(Container *self, PyObject *args, PyObject *kwds)
128{
129 if (self->container->is_running(self->container)) {
130 Py_RETURN_TRUE;
131 }
132
133 Py_RETURN_FALSE;
134}
135
136static PyObject *
137Container_state(Container *self, PyObject *args, PyObject *kwds)
138{
139 return PyUnicode_FromString(self->container->state(self->container));
140}
141
142// Container Functions
143static PyObject *
144Container_clear_config_item(Container *self, PyObject *args, PyObject *kwds)
145{
146 static char *kwlist[] = {"key", NULL};
147 char *key = NULL;
148
149 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
150 &key))
151 Py_RETURN_FALSE;
152
153 if (self->container->clear_config_item(self->container, key)) {
154 Py_RETURN_TRUE;
155 }
156
157 Py_RETURN_FALSE;
158}
159
160static PyObject *
161Container_create(Container *self, PyObject *args, PyObject *kwds)
162{
163 char* template_name = NULL;
164 char** create_args = {NULL};
165 PyObject *vargs = NULL;
166 static char *kwlist[] = {"template", "args", NULL};
167
168 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist,
169 &template_name, &vargs))
170 Py_RETURN_FALSE;
171
172 if (vargs && PyTuple_Check(vargs)) {
173 create_args = convert_tuple_to_char_pointer_array(vargs);
174 if (!create_args) {
175 return NULL;
176 }
177 }
178
179 if (self->container->create(self->container, template_name, create_args)) {
180 Py_RETURN_TRUE;
181 }
182
183 Py_RETURN_FALSE;
184}
185
186static PyObject *
187Container_destroy(Container *self, PyObject *args, PyObject *kwds)
188{
189 if (self->container->destroy(self->container)) {
190 Py_RETURN_TRUE;
191 }
192
193 Py_RETURN_FALSE;
194}
195
196static PyObject *
197Container_freeze(Container *self, PyObject *args, PyObject *kwds)
198{
199 if (self->container->freeze(self->container)) {
200 Py_RETURN_TRUE;
201 }
202
203 Py_RETURN_FALSE;
204}
205
f4d3a9fd
SG
206static PyObject *
207Container_get_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
208{
209 static char *kwlist[] = {"key", NULL};
210 char* key = NULL;
211 int len = 0;
212
213 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
214 &key))
215 Py_RETURN_FALSE;
216
217 len = self->container->get_cgroup_item(self->container, key, NULL, 0);
218
219 if (len <= 0) {
220 Py_RETURN_FALSE;
221 }
222
223 char* value = (char*) malloc(sizeof(char)*len + 1);
224 if (self->container->get_cgroup_item(self->container, key, value, len + 1) != len) {
225 Py_RETURN_FALSE;
226 }
227
228 return PyUnicode_FromString(value);
229}
230
be2e4e54
SG
231static PyObject *
232Container_get_config_item(Container *self, PyObject *args, PyObject *kwds)
233{
234 static char *kwlist[] = {"key", NULL};
235 char* key = NULL;
236 int len = 0;
237
f4d3a9fd 238 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
be2e4e54
SG
239 &key))
240 Py_RETURN_FALSE;
241
242 len = self->container->get_config_item(self->container, key, NULL, 0);
243
244 if (len <= 0) {
245 Py_RETURN_FALSE;
246 }
247
248 char* value = (char*) malloc(sizeof(char)*len + 1);
249 if (self->container->get_config_item(self->container, key, value, len + 1) != len) {
250 Py_RETURN_FALSE;
251 }
252
253 return PyUnicode_FromString(value);
254}
255
256static PyObject *
257Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
258{
259 static char *kwlist[] = {"key", NULL};
260 char* key = NULL;
261 int len = 0;
262
263 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
264 &key))
265 Py_RETURN_FALSE;
266
267 len = self->container->get_keys(self->container, key, NULL, 0);
268
269 if (len <= 0) {
270 Py_RETURN_FALSE;
271 }
272
273 char* value = (char*) malloc(sizeof(char)*len + 1);
274 if (self->container->get_keys(self->container, key, value, len + 1) != len) {
275 Py_RETURN_FALSE;
276 }
277
278 return PyUnicode_FromString(value);
279}
280
281static PyObject *
282Container_load_config(Container *self, PyObject *args, PyObject *kwds)
283{
284 static char *kwlist[] = {"path", NULL};
285 char* path = NULL;
286
287 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
288 &path))
289 Py_RETURN_FALSE;
290
291 if (self->container->load_config(self->container, path)) {
292 Py_RETURN_TRUE;
293 }
294
295 Py_RETURN_FALSE;
296}
297
298static PyObject *
299Container_save_config(Container *self, PyObject *args, PyObject *kwds)
300{
301 static char *kwlist[] = {"path", NULL};
302 char* path = NULL;
303
304 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
305 &path))
306 Py_RETURN_FALSE;
307
308 if (self->container->save_config(self->container, path)) {
309 Py_RETURN_TRUE;
310 }
311
312 Py_RETURN_FALSE;
313}
314
f4d3a9fd
SG
315static PyObject *
316Container_set_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
317{
318 static char *kwlist[] = {"key", "value", NULL};
319 char *key = NULL;
320 char *value = NULL;
321
322 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss|", kwlist,
323 &key, &value))
324 Py_RETURN_FALSE;
325
326 if (self->container->set_cgroup_item(self->container, key, value)) {
327 Py_RETURN_TRUE;
328 }
329
330 Py_RETURN_FALSE;
331}
332
be2e4e54
SG
333static PyObject *
334Container_set_config_item(Container *self, PyObject *args, PyObject *kwds)
335{
336 static char *kwlist[] = {"key", "value", NULL};
337 char *key = NULL;
338 char *value = NULL;
339
340 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss|", kwlist,
341 &key, &value))
342 Py_RETURN_FALSE;
343
344 if (self->container->set_config_item(self->container, key, value)) {
345 Py_RETURN_TRUE;
346 }
347
348 Py_RETURN_FALSE;
349}
350
351static PyObject *
352Container_shutdown(Container *self, PyObject *args, PyObject *kwds)
353{
354 static char *kwlist[] = {"timeout", NULL};
355 int timeout = -1;
356
357 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
358 &timeout))
359 Py_RETURN_FALSE;
360
361 if (self->container->shutdown(self->container, timeout)) {
362 Py_RETURN_TRUE;
363 }
364
365 Py_RETURN_FALSE;
366}
367
368static PyObject *
369Container_start(Container *self, PyObject *args, PyObject *kwds)
370{
371 char** init_args = {NULL};
372 PyObject *useinit = NULL, *vargs = NULL;
373 int init_useinit = 0;
374 static char *kwlist[] = {"useinit", "cmd", NULL};
375
376 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
377 &useinit, &vargs))
378 Py_RETURN_FALSE;
379
380 if (useinit && useinit == Py_True) {
381 init_useinit = 1;
382 }
383
384 if (vargs && PyTuple_Check(vargs)) {
385 init_args = convert_tuple_to_char_pointer_array(vargs);
386 if (!init_args) {
387 return NULL;
388 }
389 }
390
be2e4e54
SG
391 self->container->want_daemonize(self->container);
392
393 if (self->container->start(self->container, init_useinit, init_args)) {
394 Py_RETURN_TRUE;
395 }
396
397 Py_RETURN_FALSE;
398}
399
400static PyObject *
401Container_stop(Container *self, PyObject *args, PyObject *kwds)
402{
403 if (self->container->stop(self->container)) {
404 Py_RETURN_TRUE;
405 }
406
407 Py_RETURN_FALSE;
408}
409
410static PyObject *
411Container_unfreeze(Container *self, PyObject *args, PyObject *kwds)
412{
413 if (self->container->unfreeze(self->container)) {
414 Py_RETURN_TRUE;
415 }
416
417 Py_RETURN_FALSE;
418}
419
420static PyObject *
421Container_wait(Container *self, PyObject *args, PyObject *kwds)
422{
423 static char *kwlist[] = {"state", "timeout", NULL};
424 char *state = NULL;
425 int timeout = -1;
426
427 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist,
428 &state, &timeout))
429 Py_RETURN_FALSE;
430
431 if (self->container->wait(self->container, state, timeout)) {
432 Py_RETURN_TRUE;
433 }
434
435 Py_RETURN_FALSE;
436}
437
438static PyGetSetDef Container_getseters[] = {
439 {"config_file_name",
440 (getter)Container_config_file_name, 0,
441 "Path to the container configuration",
442 NULL},
443 {"defined",
444 (getter)Container_defined, 0,
445 "Boolean indicating whether the container configuration exists",
446 NULL},
447 {"init_pid",
448 (getter)Container_init_pid, 0,
449 "PID of the container's init process in the host's PID namespace",
450 NULL},
451 {"name",
452 (getter)Container_name, 0,
453 "Container name",
454 NULL},
455 {"running",
456 (getter)Container_running, 0,
457 "Boolean indicating whether the container is running or not",
458 NULL},
459 {"state",
460 (getter)Container_state, 0,
461 "Container state",
462 NULL},
463};
464
465static PyMethodDef Container_methods[] = {
466 {"clear_config_item", (PyCFunction)Container_clear_config_item, METH_VARARGS | METH_KEYWORDS,
467 "clear_config_item(key) -> boolean\n"
468 "\n"
469 "Clear the current value of a config key."
470 },
471 {"create", (PyCFunction)Container_create, METH_VARARGS | METH_KEYWORDS,
472 "create(template, args = (,)) -> boolean\n"
473 "\n"
474 "Create a new rootfs for the container, using the given template "
475 "and passing some optional arguments to it."
476 },
477 {"destroy", (PyCFunction)Container_destroy, METH_NOARGS,
478 "destroy() -> boolean\n"
479 "\n"
480 "Destroys the container."
481 },
482 {"freeze", (PyCFunction)Container_freeze, METH_NOARGS,
483 "freeze() -> boolean\n"
484 "\n"
485 "Freezes the container and returns its return code."
486 },
f4d3a9fd
SG
487 {"get_cgroup_item", (PyCFunction)Container_get_cgroup_item, METH_VARARGS | METH_KEYWORDS,
488 "get_cgroup_item(key) -> string\n"
489 "\n"
490 "Get the current value of a cgroup entry."
491 },
be2e4e54
SG
492 {"get_config_item", (PyCFunction)Container_get_config_item, METH_VARARGS | METH_KEYWORDS,
493 "get_config_item(key) -> string\n"
494 "\n"
495 "Get the current value of a config key."
496 },
497 {"get_keys", (PyCFunction)Container_get_keys, METH_VARARGS | METH_KEYWORDS,
498 "get_keys(key) -> string\n"
499 "\n"
500 "Get a list of valid sub-keys for a key."
501 },
502 {"load_config", (PyCFunction)Container_load_config, METH_VARARGS | METH_KEYWORDS,
503 "load_config(path = DEFAULT) -> boolean\n"
504 "\n"
505 "Read the container configuration from its default "
506 "location or from an alternative location if provided."
507 },
508 {"save_config", (PyCFunction)Container_save_config, METH_VARARGS | METH_KEYWORDS,
509 "save_config(path = DEFAULT) -> boolean\n"
510 "\n"
511 "Save the container configuration to its default "
512 "location or to an alternative location if provided."
513 },
f4d3a9fd
SG
514 {"set_cgroup_item", (PyCFunction)Container_set_cgroup_item, METH_VARARGS | METH_KEYWORDS,
515 "set_cgroup_item(key, value) -> boolean\n"
516 "\n"
517 "Set a cgroup entry to the provided value."
518 },
be2e4e54
SG
519 {"set_config_item", (PyCFunction)Container_set_config_item, METH_VARARGS | METH_KEYWORDS,
520 "set_config_item(key, value) -> boolean\n"
521 "\n"
522 "Set a config key to the provided value."
523 },
524 {"shutdown", (PyCFunction)Container_shutdown, METH_VARARGS | METH_KEYWORDS,
525 "shutdown(timeout = -1) -> boolean\n"
526 "\n"
527 "Sends SIGPWR to the container and wait for it to shutdown "
528 "unless timeout is set to a positive value, in which case "
529 "the container will be killed when the timeout is reached."
530 },
531 {"start", (PyCFunction)Container_start, METH_VARARGS | METH_KEYWORDS,
532 "start(useinit = False, cmd = (,)) -> boolean\n"
533 "\n"
e2611fd5 534 "Start the container, optionally using lxc-init and "
be2e4e54
SG
535 "an alternate init command, then returns its return code."
536 },
537 {"stop", (PyCFunction)Container_stop, METH_NOARGS,
538 "stop() -> boolean\n"
539 "\n"
540 "Stop the container and returns its return code."
541 },
542 {"unfreeze", (PyCFunction)Container_unfreeze, METH_NOARGS,
543 "unfreeze() -> boolean\n"
544 "\n"
545 "Unfreezes the container and returns its return code."
546 },
547 {"wait", (PyCFunction)Container_wait, METH_VARARGS | METH_KEYWORDS,
548 "wait(state, timeout = -1) -> boolean\n"
549 "\n"
550 "Wait for the container to reach a given state or timeout."
551 },
552 {NULL} /* Sentinel */
553};
554
555static PyTypeObject _lxc_ContainerType = {
556PyVarObject_HEAD_INIT(NULL, 0)
557 "lxc.Container", /* tp_name */
558 sizeof(Container), /* tp_basicsize */
559 0, /* tp_itemsize */
560 (destructor)Container_dealloc, /* tp_dealloc */
561 0, /* tp_print */
562 0, /* tp_getattr */
563 0, /* tp_setattr */
564 0, /* tp_reserved */
565 0, /* tp_repr */
566 0, /* tp_as_number */
567 0, /* tp_as_sequence */
568 0, /* tp_as_mapping */
569 0, /* tp_hash */
570 0, /* tp_call */
571 0, /* tp_str */
572 0, /* tp_getattro */
573 0, /* tp_setattro */
574 0, /* tp_as_buffer */
575 Py_TPFLAGS_DEFAULT |
576 Py_TPFLAGS_BASETYPE, /* tp_flags */
577 "Container objects", /* tp_doc */
578 0, /* tp_traverse */
579 0, /* tp_clear */
580 0, /* tp_richcompare */
581 0, /* tp_weaklistoffset */
582 0, /* tp_iter */
583 0, /* tp_iternext */
584 Container_methods, /* tp_methods */
585 0, /* tp_members */
586 Container_getseters, /* tp_getset */
587 0, /* tp_base */
588 0, /* tp_dict */
589 0, /* tp_descr_get */
590 0, /* tp_descr_set */
591 0, /* tp_dictoffset */
592 (initproc)Container_init, /* tp_init */
593 0, /* tp_alloc */
594 Container_new, /* tp_new */
595};
596
597static PyModuleDef _lxcmodule = {
598 PyModuleDef_HEAD_INIT,
599 "_lxc",
600 "Binding for liblxc in python",
601 -1,
602 NULL, NULL, NULL, NULL, NULL
603};
604
605PyMODINIT_FUNC
606PyInit__lxc(void)
607{
608 PyObject* m;
609
610 if (PyType_Ready(&_lxc_ContainerType) < 0)
611 return NULL;
612
613 m = PyModule_Create(&_lxcmodule);
614 if (m == NULL)
615 return NULL;
616
617 Py_INCREF(&_lxc_ContainerType);
618 PyModule_AddObject(m, "Container", (PyObject *)&_lxc_ContainerType);
619 return m;
620}