]> git.proxmox.com Git - mirror_lxc.git/blame - src/python-lxc/lxc.c
console API improvements
[mirror_lxc.git] / src / python-lxc / lxc.c
CommitLineData
be2e4e54
SG
1/*
2 * python-lxc: Python bindings for LXC
3 *
e649c803 4 * (C) Copyright Canonical Ltd. 2012-2013
be2e4e54
SG
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) {
2ebec36f 37 int argc = PyTuple_GET_SIZE(argv);
6516ad8b 38 int i, j;
be2e4e54
SG
39
40 char **result = (char**) malloc(sizeof(char*)*argc + 1);
41
2ebec36f
SG
42 if (result == NULL) {
43 PyErr_SetNone(PyExc_MemoryError);
44 return NULL;
45 }
46
be2e4e54 47 for (i = 0; i < argc; i++) {
2ebec36f
SG
48 PyObject *pyobj = PyTuple_GET_ITEM(argv, i);
49 assert(pyobj != NULL);
be2e4e54
SG
50
51 char *str = NULL;
15451ecf 52 PyObject *pystr = NULL;
6516ad8b 53
be2e4e54
SG
54 if (!PyUnicode_Check(pyobj)) {
55 PyErr_SetString(PyExc_ValueError, "Expected a string");
6516ad8b 56 goto error;
be2e4e54
SG
57 }
58
15451ecf
SG
59 pystr = PyUnicode_AsUTF8String(pyobj);
60 if (!pystr) {
6516ad8b
SG
61 /* Maybe it wasn't UTF-8 encoded. An exception is already set. */
62 goto error;
2ebec36f
SG
63 }
64
15451ecf
SG
65 str = PyBytes_AsString(pystr);
66 if (!str) {
67 /* Maybe pystr wasn't a valid object. An exception is already set.
68 */
69 Py_DECREF(pystr);
70 goto error;
71 }
72
6516ad8b
SG
73 /* We must make a copy of str, because it points into internal memory
74 * which we do not own. Assume it's NULL terminated, otherwise we'd
75 * have to use PyUnicode_AsUTF8AndSize() and be explicit about copying
76 * the memory.
77 */
78 result[i] = strdup(str);
2ebec36f 79
6516ad8b
SG
80 /* Do not decref pyobj since we stole a reference by using
81 * PyTuple_GET_ITEM().
82 */
15451ecf 83 Py_DECREF(pystr);
6516ad8b
SG
84 if (result[i] == NULL) {
85 PyErr_SetNone(PyExc_MemoryError);
86 goto error;
87 }
be2e4e54
SG
88 }
89
90 result[argc] = NULL;
be2e4e54 91 return result;
6516ad8b
SG
92
93error:
94 /* We can only iterate up to but not including i because malloc() does not
95 * initialize its memory. Thus if we got here, i points to the index
96 * after the last strdup'd entry in result.
97 */
98 for (j = 0; j < i; j++)
99 free(result[j]);
100 free(result);
101 return NULL;
be2e4e54
SG
102}
103
be2e4e54
SG
104static void
105Container_dealloc(Container* self)
106{
e649c803 107 lxc_container_put(self->container);
be2e4e54
SG
108 Py_TYPE(self)->tp_free((PyObject*)self);
109}
110
111static PyObject *
112Container_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
113{
114 Container *self;
115
116 self = (Container *)type->tp_alloc(type, 0);
117
118 return (PyObject *)self;
119}
120
121static int
122Container_init(Container *self, PyObject *args, PyObject *kwds)
123{
edb09f8d 124 static char *kwlist[] = {"name", "config_path", NULL};
be2e4e54 125 char *name = NULL;
2ebec36f 126 PyObject *fs_config_path = NULL;
edb09f8d 127 char *config_path = NULL;
be2e4e54 128
2ebec36f
SG
129 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O&", kwlist,
130 &name,
131 PyUnicode_FSConverter, &fs_config_path))
be2e4e54
SG
132 return -1;
133
2ebec36f
SG
134 if (fs_config_path != NULL) {
135 config_path = PyBytes_AS_STRING(fs_config_path);
136 assert(config_path != NULL);
137 }
138
edb09f8d 139 self->container = lxc_container_new(name, config_path);
be2e4e54 140 if (!self->container) {
2ebec36f
SG
141 Py_XDECREF(fs_config_path);
142 fprintf(stderr, "%d: error creating container %s\n", __LINE__, name);
be2e4e54
SG
143 return -1;
144 }
145
2ebec36f 146 Py_XDECREF(fs_config_path);
be2e4e54
SG
147 return 0;
148}
149
24fcdb39 150static PyObject *
1fbb470b 151LXC_get_default_config_path(PyObject *self, PyObject *args)
24fcdb39
SG
152{
153 return PyUnicode_FromString(lxc_get_default_config_path());
154}
155
b6adc92b 156static PyObject *
1fbb470b 157LXC_get_version(PyObject *self, PyObject *args)
b6adc92b
SG
158{
159 return PyUnicode_FromString(lxc_get_version());
160}
161
be2e4e54
SG
162// Container properties
163static PyObject *
2ebec36f 164Container_config_file_name(Container *self, void *closure)
be2e4e54 165{
2ebec36f
SG
166 return PyUnicode_FromString(
167 self->container->config_file_name(self->container));
be2e4e54
SG
168}
169
170static PyObject *
2ebec36f 171Container_defined(Container *self, void *closure)
be2e4e54
SG
172{
173 if (self->container->is_defined(self->container)) {
174 Py_RETURN_TRUE;
175 }
176
177 Py_RETURN_FALSE;
178}
179
180static PyObject *
2ebec36f 181Container_init_pid(Container *self, void *closure)
be2e4e54 182{
2ebec36f 183 return PyLong_FromLong(self->container->init_pid(self->container));
be2e4e54
SG
184}
185
186static PyObject *
2ebec36f 187Container_name(Container *self, void *closure)
be2e4e54
SG
188{
189 return PyUnicode_FromString(self->container->name);
190}
191
192static PyObject *
2ebec36f 193Container_running(Container *self, void *closure)
be2e4e54
SG
194{
195 if (self->container->is_running(self->container)) {
196 Py_RETURN_TRUE;
197 }
198
199 Py_RETURN_FALSE;
200}
201
202static PyObject *
2ebec36f 203Container_state(Container *self, void *closure)
be2e4e54
SG
204{
205 return PyUnicode_FromString(self->container->state(self->container));
206}
207
208// Container Functions
209static PyObject *
210Container_clear_config_item(Container *self, PyObject *args, PyObject *kwds)
211{
212 static char *kwlist[] = {"key", NULL};
213 char *key = NULL;
214
2ebec36f 215 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
be2e4e54 216 &key))
2ebec36f 217 return NULL;
be2e4e54
SG
218
219 if (self->container->clear_config_item(self->container, key)) {
220 Py_RETURN_TRUE;
221 }
222
223 Py_RETURN_FALSE;
224}
225
226static PyObject *
227Container_create(Container *self, PyObject *args, PyObject *kwds)
228{
229 char* template_name = NULL;
230 char** create_args = {NULL};
2ebec36f 231 PyObject *retval = NULL, *vargs = NULL;
6516ad8b 232 int i = 0;
be2e4e54
SG
233 static char *kwlist[] = {"template", "args", NULL};
234
235 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist,
236 &template_name, &vargs))
2ebec36f
SG
237 return NULL;
238
239 if (vargs) {
240 if (PyTuple_Check(vargs)) {
241 create_args = convert_tuple_to_char_pointer_array(vargs);
242 if (!create_args) {
243 return NULL;
244 }
245 }
246 else {
247 PyErr_SetString(PyExc_ValueError, "args needs to be a tuple");
be2e4e54
SG
248 return NULL;
249 }
250 }
251
1897e3bc 252 if (self->container->create(self->container, template_name, NULL, NULL, create_args))
2ebec36f
SG
253 retval = Py_True;
254 else
255 retval = Py_False;
256
257 if (vargs) {
258 /* We cannot have gotten here unless vargs was given and create_args
259 * was successfully allocated.
260 */
6516ad8b
SG
261 for (i = 0; i < PyTuple_GET_SIZE(vargs); i++)
262 free(create_args[i]);
e649c803 263 free(create_args);
be2e4e54
SG
264 }
265
2ebec36f
SG
266 Py_INCREF(retval);
267 return retval;
be2e4e54
SG
268}
269
270static PyObject *
271Container_destroy(Container *self, PyObject *args, PyObject *kwds)
272{
273 if (self->container->destroy(self->container)) {
274 Py_RETURN_TRUE;
275 }
276
277 Py_RETURN_FALSE;
278}
279
280static PyObject *
281Container_freeze(Container *self, PyObject *args, PyObject *kwds)
282{
283 if (self->container->freeze(self->container)) {
284 Py_RETURN_TRUE;
285 }
286
287 Py_RETURN_FALSE;
288}
289
f4d3a9fd
SG
290static PyObject *
291Container_get_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
292{
293 static char *kwlist[] = {"key", NULL};
294 char* key = NULL;
295 int len = 0;
e649c803 296 PyObject *ret = NULL;
f4d3a9fd 297
2ebec36f 298 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
f4d3a9fd 299 &key))
2ebec36f 300 return NULL;
f4d3a9fd
SG
301
302 len = self->container->get_cgroup_item(self->container, key, NULL, 0);
303
2ebec36f
SG
304 if (len < 0) {
305 PyErr_SetString(PyExc_KeyError, "Invalid cgroup entry");
306 return NULL;
f4d3a9fd
SG
307 }
308
309 char* value = (char*) malloc(sizeof(char)*len + 1);
2ebec36f
SG
310 if (value == NULL)
311 return PyErr_NoMemory();
312
313 if (self->container->get_cgroup_item(self->container,
314 key, value, len + 1) != len) {
315 PyErr_SetString(PyExc_ValueError, "Unable to read config value");
e649c803 316 free(value);
2ebec36f 317 return NULL;
f4d3a9fd
SG
318 }
319
e649c803
SG
320 ret = PyUnicode_FromString(value);
321 free(value);
322 return ret;
f4d3a9fd
SG
323}
324
be2e4e54
SG
325static PyObject *
326Container_get_config_item(Container *self, PyObject *args, PyObject *kwds)
327{
328 static char *kwlist[] = {"key", NULL};
329 char* key = NULL;
330 int len = 0;
e649c803 331 PyObject *ret = NULL;
be2e4e54 332
f4d3a9fd 333 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist,
be2e4e54 334 &key))
2ebec36f 335 return NULL;
be2e4e54
SG
336
337 len = self->container->get_config_item(self->container, key, NULL, 0);
338
2ebec36f
SG
339 if (len < 0) {
340 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
341 return NULL;
be2e4e54
SG
342 }
343
344 char* value = (char*) malloc(sizeof(char)*len + 1);
2ebec36f
SG
345 if (value == NULL)
346 return PyErr_NoMemory();
347
348 if (self->container->get_config_item(self->container,
349 key, value, len + 1) != len) {
350 PyErr_SetString(PyExc_ValueError, "Unable to read config value");
351 free(value);
352 return NULL;
be2e4e54
SG
353 }
354
e649c803
SG
355 ret = PyUnicode_FromString(value);
356 free(value);
357 return ret;
be2e4e54
SG
358}
359
edb09f8d
SG
360static PyObject *
361Container_get_config_path(Container *self, PyObject *args, PyObject *kwds)
362{
2ebec36f
SG
363 return PyUnicode_FromString(
364 self->container->get_config_path(self->container));
edb09f8d
SG
365}
366
be2e4e54
SG
367static PyObject *
368Container_get_keys(Container *self, PyObject *args, PyObject *kwds)
369{
370 static char *kwlist[] = {"key", NULL};
371 char* key = NULL;
372 int len = 0;
e649c803 373 PyObject *ret = NULL;
be2e4e54
SG
374
375 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist,
376 &key))
2ebec36f 377 return NULL;
be2e4e54
SG
378
379 len = self->container->get_keys(self->container, key, NULL, 0);
380
2ebec36f
SG
381 if (len < 0) {
382 PyErr_SetString(PyExc_KeyError, "Invalid configuration key");
383 return NULL;
be2e4e54
SG
384 }
385
386 char* value = (char*) malloc(sizeof(char)*len + 1);
2ebec36f
SG
387 if (value == NULL)
388 return PyErr_NoMemory();
389
390 if (self->container->get_keys(self->container,
391 key, value, len + 1) != len) {
392 PyErr_SetString(PyExc_ValueError, "Unable to read config keys");
e649c803 393 free(value);
2ebec36f 394 return NULL;
be2e4e54
SG
395 }
396
e649c803
SG
397 ret = PyUnicode_FromString(value);
398 free(value);
399 return ret;
be2e4e54
SG
400}
401
9c83a661
SG
402static PyObject *
403Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
404{
405 static char *kwlist[] = {"interface", "family", "scope", NULL};
406 char* interface = NULL;
407 char* family = NULL;
408 int scope = 0;
409
410 int i = 0;
411 char** ips = NULL;
412
413 PyObject* ret;
414
415 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|ssi", kwlist,
416 &interface, &family, &scope))
417 return NULL;
418
419 /* Get the IPs */
420 ips = self->container->get_ips(self->container, interface, family, scope);
421 if (!ips)
422 return PyTuple_New(0);
423
424 /* Count the entries */
425 while (ips[i])
426 i++;
427
428 /* Create the new tuple */
429 ret = PyTuple_New(i);
430 if (!ret)
431 return NULL;
432
433 /* Add the entries to the tuple and free the memory */
434 i = 0;
435 while (ips[i]) {
436 PyObject *unicode = PyUnicode_FromString(ips[i]);
437 if (!unicode) {
438 Py_DECREF(ret);
439 ret = NULL;
440 break;
441 }
442 PyTuple_SET_ITEM(ret, i, unicode);
443 i++;
444 }
445
446 /* Free the list of IPs */
447 i = 0;
448 while (ips[i]) {
449 free(ips[i]);
450 i++;
451 }
452 free(ips);
453
454 return ret;
455}
456
be2e4e54
SG
457static PyObject *
458Container_load_config(Container *self, PyObject *args, PyObject *kwds)
459{
460 static char *kwlist[] = {"path", NULL};
2ebec36f 461 PyObject *fs_path = NULL;
be2e4e54
SG
462 char* path = NULL;
463
2ebec36f
SG
464 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
465 PyUnicode_FSConverter, &fs_path))
466 return NULL;
467
468 if (fs_path != NULL) {
469 path = PyBytes_AS_STRING(fs_path);
470 assert(path != NULL);
471 }
be2e4e54
SG
472
473 if (self->container->load_config(self->container, path)) {
2ebec36f 474 Py_XDECREF(fs_path);
be2e4e54
SG
475 Py_RETURN_TRUE;
476 }
477
2ebec36f 478 Py_XDECREF(fs_path);
be2e4e54
SG
479 Py_RETURN_FALSE;
480}
481
482static PyObject *
483Container_save_config(Container *self, PyObject *args, PyObject *kwds)
484{
485 static char *kwlist[] = {"path", NULL};
2ebec36f 486 PyObject *fs_path = NULL;
be2e4e54
SG
487 char* path = NULL;
488
2ebec36f
SG
489 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
490 PyUnicode_FSConverter, &fs_path))
491 return NULL;
492
493 if (fs_path != NULL) {
494 path = PyBytes_AS_STRING(fs_path);
495 assert(path != NULL);
496 }
be2e4e54
SG
497
498 if (self->container->save_config(self->container, path)) {
2ebec36f 499 Py_XDECREF(fs_path);
be2e4e54
SG
500 Py_RETURN_TRUE;
501 }
502
2ebec36f 503 Py_XDECREF(fs_path);
be2e4e54
SG
504 Py_RETURN_FALSE;
505}
506
f4d3a9fd
SG
507static PyObject *
508Container_set_cgroup_item(Container *self, PyObject *args, PyObject *kwds)
509{
510 static char *kwlist[] = {"key", "value", NULL};
511 char *key = NULL;
512 char *value = NULL;
513
2ebec36f 514 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
f4d3a9fd 515 &key, &value))
2ebec36f 516 return NULL;
f4d3a9fd
SG
517
518 if (self->container->set_cgroup_item(self->container, key, value)) {
519 Py_RETURN_TRUE;
520 }
521
522 Py_RETURN_FALSE;
523}
524
be2e4e54
SG
525static PyObject *
526Container_set_config_item(Container *self, PyObject *args, PyObject *kwds)
527{
528 static char *kwlist[] = {"key", "value", NULL};
529 char *key = NULL;
530 char *value = NULL;
531
2ebec36f 532 if (! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
be2e4e54 533 &key, &value))
2ebec36f 534 return NULL;
be2e4e54
SG
535
536 if (self->container->set_config_item(self->container, key, value)) {
537 Py_RETURN_TRUE;
538 }
539
540 Py_RETURN_FALSE;
541}
542
edb09f8d
SG
543static PyObject *
544Container_set_config_path(Container *self, PyObject *args, PyObject *kwds)
545{
546 static char *kwlist[] = {"path", NULL};
547 char *path = NULL;
548
2ebec36f 549 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
edb09f8d 550 &path))
2ebec36f 551 return NULL;
edb09f8d
SG
552
553 if (self->container->set_config_path(self->container, path)) {
554 Py_RETURN_TRUE;
555 }
556
557 Py_RETURN_FALSE;
558}
559
be2e4e54
SG
560static PyObject *
561Container_shutdown(Container *self, PyObject *args, PyObject *kwds)
562{
563 static char *kwlist[] = {"timeout", NULL};
564 int timeout = -1;
565
566 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
567 &timeout))
2ebec36f 568 return NULL;
be2e4e54
SG
569
570 if (self->container->shutdown(self->container, timeout)) {
571 Py_RETURN_TRUE;
572 }
573
574 Py_RETURN_FALSE;
575}
576
577static PyObject *
578Container_start(Container *self, PyObject *args, PyObject *kwds)
579{
580 char** init_args = {NULL};
2ebec36f 581 PyObject *useinit = NULL, *retval = NULL, *vargs = NULL;
6516ad8b 582 int init_useinit = 0, i = 0;
be2e4e54
SG
583 static char *kwlist[] = {"useinit", "cmd", NULL};
584
585 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist,
586 &useinit, &vargs))
2ebec36f 587 return NULL;
be2e4e54
SG
588
589 if (useinit && useinit == Py_True) {
590 init_useinit = 1;
591 }
592
593 if (vargs && PyTuple_Check(vargs)) {
594 init_args = convert_tuple_to_char_pointer_array(vargs);
595 if (!init_args) {
596 return NULL;
597 }
598 }
599
be2e4e54
SG
600 self->container->want_daemonize(self->container);
601
2ebec36f
SG
602 if (self->container->start(self->container, init_useinit, init_args))
603 retval = Py_True;
604 else
605 retval = Py_False;
606
607 if (vargs) {
608 /* We cannot have gotten here unless vargs was given and create_args
609 * was successfully allocated.
610 */
6516ad8b
SG
611 for (i = 0; i < PyTuple_GET_SIZE(vargs); i++)
612 free(init_args[i]);
e649c803 613 free(init_args);
be2e4e54
SG
614 }
615
2ebec36f
SG
616 Py_INCREF(retval);
617 return retval;
be2e4e54
SG
618}
619
620static PyObject *
621Container_stop(Container *self, PyObject *args, PyObject *kwds)
622{
623 if (self->container->stop(self->container)) {
624 Py_RETURN_TRUE;
625 }
626
627 Py_RETURN_FALSE;
628}
629
630static PyObject *
631Container_unfreeze(Container *self, PyObject *args, PyObject *kwds)
632{
633 if (self->container->unfreeze(self->container)) {
634 Py_RETURN_TRUE;
635 }
636
637 Py_RETURN_FALSE;
638}
639
b5159817
DE
640static PyObject *
641Container_console(Container *self, PyObject *args, PyObject *kwds)
642{
643 static char *kwlist[] = {"ttynum", "stdinfd", "stdoutfd", "stderrfd", "escape", NULL};
644 int ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 1;
645
646 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|iiiii", kwlist,
647 &ttynum, &stdinfd, &stdoutfd, &stderrfd,
648 &escape))
649 return NULL;
650
651 if (self->container->console(self->container, ttynum,
652 stdinfd, stdoutfd, stderrfd, escape) == 0) {
653 Py_RETURN_TRUE;
654 }
655 Py_RETURN_FALSE;
656}
657
658static PyObject *
659Container_console_getfd(Container *self, PyObject *args, PyObject *kwds)
660{
661 static char *kwlist[] = {"ttynum", NULL};
662 int ttynum = -1, masterfd;
663
664 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &ttynum))
665 return NULL;
666
667 if (self->container->console_getfd(self->container, &ttynum, &masterfd) < 0) {
668 PyErr_SetString(PyExc_ValueError, "Unable to allocate tty");
669 return NULL;
670 }
671 return PyLong_FromLong(masterfd);
672}
673
be2e4e54
SG
674static PyObject *
675Container_wait(Container *self, PyObject *args, PyObject *kwds)
676{
677 static char *kwlist[] = {"state", "timeout", NULL};
678 char *state = NULL;
679 int timeout = -1;
680
681 if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist,
682 &state, &timeout))
2ebec36f 683 return NULL;
be2e4e54
SG
684
685 if (self->container->wait(self->container, state, timeout)) {
686 Py_RETURN_TRUE;
687 }
688
689 Py_RETURN_FALSE;
690}
691
692static PyGetSetDef Container_getseters[] = {
693 {"config_file_name",
2ebec36f 694 (getter)Container_config_file_name, NULL,
be2e4e54
SG
695 "Path to the container configuration",
696 NULL},
697 {"defined",
2ebec36f 698 (getter)Container_defined, NULL,
be2e4e54
SG
699 "Boolean indicating whether the container configuration exists",
700 NULL},
701 {"init_pid",
2ebec36f 702 (getter)Container_init_pid, NULL,
be2e4e54
SG
703 "PID of the container's init process in the host's PID namespace",
704 NULL},
705 {"name",
2ebec36f 706 (getter)Container_name, NULL,
be2e4e54
SG
707 "Container name",
708 NULL},
709 {"running",
2ebec36f 710 (getter)Container_running, NULL,
be2e4e54
SG
711 "Boolean indicating whether the container is running or not",
712 NULL},
713 {"state",
2ebec36f 714 (getter)Container_state, NULL,
be2e4e54
SG
715 "Container state",
716 NULL},
1fbb470b 717 {NULL, NULL, NULL, NULL, NULL}
be2e4e54
SG
718};
719
720static PyMethodDef Container_methods[] = {
2ebec36f
SG
721 {"clear_config_item", (PyCFunction)Container_clear_config_item,
722 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
723 "clear_config_item(key) -> boolean\n"
724 "\n"
725 "Clear the current value of a config key."
726 },
2ebec36f
SG
727 {"create", (PyCFunction)Container_create,
728 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
729 "create(template, args = (,)) -> boolean\n"
730 "\n"
731 "Create a new rootfs for the container, using the given template "
732 "and passing some optional arguments to it."
733 },
2ebec36f
SG
734 {"destroy", (PyCFunction)Container_destroy,
735 METH_NOARGS,
be2e4e54
SG
736 "destroy() -> boolean\n"
737 "\n"
738 "Destroys the container."
739 },
2ebec36f
SG
740 {"freeze", (PyCFunction)Container_freeze,
741 METH_NOARGS,
be2e4e54
SG
742 "freeze() -> boolean\n"
743 "\n"
744 "Freezes the container and returns its return code."
745 },
2ebec36f
SG
746 {"get_cgroup_item", (PyCFunction)Container_get_cgroup_item,
747 METH_VARARGS|METH_KEYWORDS,
f4d3a9fd
SG
748 "get_cgroup_item(key) -> string\n"
749 "\n"
750 "Get the current value of a cgroup entry."
751 },
2ebec36f
SG
752 {"get_config_item", (PyCFunction)Container_get_config_item,
753 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
754 "get_config_item(key) -> string\n"
755 "\n"
756 "Get the current value of a config key."
757 },
2ebec36f
SG
758 {"get_config_path", (PyCFunction)Container_get_config_path,
759 METH_NOARGS,
edb09f8d
SG
760 "get_config_path() -> string\n"
761 "\n"
762 "Return the LXC config path (where the containers are stored)."
763 },
2ebec36f
SG
764 {"get_keys", (PyCFunction)Container_get_keys,
765 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
766 "get_keys(key) -> string\n"
767 "\n"
768 "Get a list of valid sub-keys for a key."
769 },
9c83a661
SG
770 {"get_ips", (PyCFunction)Container_get_ips,
771 METH_VARARGS|METH_KEYWORDS,
772 "get_ips(interface, family, scope) -> tuple\n"
773 "\n"
774 "Get a tuple of IPs for the container."
775 },
2ebec36f
SG
776 {"load_config", (PyCFunction)Container_load_config,
777 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
778 "load_config(path = DEFAULT) -> boolean\n"
779 "\n"
780 "Read the container configuration from its default "
781 "location or from an alternative location if provided."
782 },
2ebec36f
SG
783 {"save_config", (PyCFunction)Container_save_config,
784 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
785 "save_config(path = DEFAULT) -> boolean\n"
786 "\n"
787 "Save the container configuration to its default "
788 "location or to an alternative location if provided."
789 },
2ebec36f
SG
790 {"set_cgroup_item", (PyCFunction)Container_set_cgroup_item,
791 METH_VARARGS|METH_KEYWORDS,
f4d3a9fd
SG
792 "set_cgroup_item(key, value) -> boolean\n"
793 "\n"
794 "Set a cgroup entry to the provided value."
795 },
2ebec36f
SG
796 {"set_config_item", (PyCFunction)Container_set_config_item,
797 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
798 "set_config_item(key, value) -> boolean\n"
799 "\n"
800 "Set a config key to the provided value."
801 },
2ebec36f
SG
802 {"set_config_path", (PyCFunction)Container_set_config_path,
803 METH_VARARGS|METH_KEYWORDS,
edb09f8d
SG
804 "set_config_path(path) -> boolean\n"
805 "\n"
806 "Set the LXC config path (where the containers are stored)."
807 },
2ebec36f
SG
808 {"shutdown", (PyCFunction)Container_shutdown,
809 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
810 "shutdown(timeout = -1) -> boolean\n"
811 "\n"
812 "Sends SIGPWR to the container and wait for it to shutdown "
813 "unless timeout is set to a positive value, in which case "
814 "the container will be killed when the timeout is reached."
815 },
2ebec36f
SG
816 {"start", (PyCFunction)Container_start,
817 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
818 "start(useinit = False, cmd = (,)) -> boolean\n"
819 "\n"
e2611fd5 820 "Start the container, optionally using lxc-init and "
be2e4e54
SG
821 "an alternate init command, then returns its return code."
822 },
2ebec36f
SG
823 {"stop", (PyCFunction)Container_stop,
824 METH_NOARGS,
be2e4e54
SG
825 "stop() -> boolean\n"
826 "\n"
827 "Stop the container and returns its return code."
828 },
2ebec36f
SG
829 {"unfreeze", (PyCFunction)Container_unfreeze,
830 METH_NOARGS,
be2e4e54
SG
831 "unfreeze() -> boolean\n"
832 "\n"
833 "Unfreezes the container and returns its return code."
834 },
2ebec36f
SG
835 {"wait", (PyCFunction)Container_wait,
836 METH_VARARGS|METH_KEYWORDS,
be2e4e54
SG
837 "wait(state, timeout = -1) -> boolean\n"
838 "\n"
839 "Wait for the container to reach a given state or timeout."
840 },
b5159817
DE
841 {"console", (PyCFunction)Container_console,
842 METH_VARARGS|METH_KEYWORDS,
843 "console(ttynum = -1, stdinfd = 0, stdoutfd = 1, stderrfd = 2, escape = 0) -> boolean\n"
844 "\n"
845 "Attach to container's console."
846 },
847 {"console_getfd", (PyCFunction)Container_console_getfd,
848 METH_VARARGS|METH_KEYWORDS,
849 "console(ttynum = -1) -> boolean\n"
850 "\n"
851 "Attach to container's console."
852 },
1fbb470b 853 {NULL, NULL, 0, NULL}
be2e4e54
SG
854};
855
856static PyTypeObject _lxc_ContainerType = {
857PyVarObject_HEAD_INIT(NULL, 0)
858 "lxc.Container", /* tp_name */
859 sizeof(Container), /* tp_basicsize */
860 0, /* tp_itemsize */
861 (destructor)Container_dealloc, /* tp_dealloc */
862 0, /* tp_print */
863 0, /* tp_getattr */
864 0, /* tp_setattr */
865 0, /* tp_reserved */
866 0, /* tp_repr */
867 0, /* tp_as_number */
868 0, /* tp_as_sequence */
869 0, /* tp_as_mapping */
870 0, /* tp_hash */
871 0, /* tp_call */
872 0, /* tp_str */
873 0, /* tp_getattro */
874 0, /* tp_setattro */
875 0, /* tp_as_buffer */
876 Py_TPFLAGS_DEFAULT |
877 Py_TPFLAGS_BASETYPE, /* tp_flags */
878 "Container objects", /* tp_doc */
879 0, /* tp_traverse */
880 0, /* tp_clear */
881 0, /* tp_richcompare */
882 0, /* tp_weaklistoffset */
883 0, /* tp_iter */
884 0, /* tp_iternext */
885 Container_methods, /* tp_methods */
886 0, /* tp_members */
887 Container_getseters, /* tp_getset */
888 0, /* tp_base */
889 0, /* tp_dict */
890 0, /* tp_descr_get */
891 0, /* tp_descr_set */
892 0, /* tp_dictoffset */
893 (initproc)Container_init, /* tp_init */
894 0, /* tp_alloc */
895 Container_new, /* tp_new */
896};
897
24fcdb39 898static PyMethodDef LXC_methods[] = {
1fbb470b 899 {"get_default_config_path", (PyCFunction)LXC_get_default_config_path, METH_NOARGS,
24fcdb39 900 "Returns the current LXC config path"},
1fbb470b 901 {"get_version", (PyCFunction)LXC_get_version, METH_NOARGS,
b6adc92b 902 "Returns the current LXC library version"},
24fcdb39
SG
903 {NULL, NULL, 0, NULL}
904};
905
be2e4e54
SG
906static PyModuleDef _lxcmodule = {
907 PyModuleDef_HEAD_INIT,
908 "_lxc",
909 "Binding for liblxc in python",
910 -1,
24fcdb39 911 LXC_methods
be2e4e54
SG
912};
913
914PyMODINIT_FUNC
915PyInit__lxc(void)
916{
917 PyObject* m;
918
919 if (PyType_Ready(&_lxc_ContainerType) < 0)
920 return NULL;
921
922 m = PyModule_Create(&_lxcmodule);
923 if (m == NULL)
924 return NULL;
925
926 Py_INCREF(&_lxc_ContainerType);
927 PyModule_AddObject(m, "Container", (PyObject *)&_lxc_ContainerType);
928 return m;
929}