]>
Commit | Line | Data |
---|---|---|
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 | ||
30 | typedef struct { | |
31 | PyObject_HEAD | |
32 | struct lxc_container *container; | |
33 | } Container; | |
34 | ||
35 | char** | |
36 | convert_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 | |
93 | error: | |
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 |
104 | static void |
105 | Container_dealloc(Container* self) | |
106 | { | |
e649c803 | 107 | lxc_container_put(self->container); |
be2e4e54 SG |
108 | Py_TYPE(self)->tp_free((PyObject*)self); |
109 | } | |
110 | ||
111 | static PyObject * | |
112 | Container_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 | ||
121 | static int | |
122 | Container_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 | 150 | static PyObject * |
1fbb470b | 151 | LXC_get_default_config_path(PyObject *self, PyObject *args) |
24fcdb39 SG |
152 | { |
153 | return PyUnicode_FromString(lxc_get_default_config_path()); | |
154 | } | |
155 | ||
b6adc92b | 156 | static PyObject * |
1fbb470b | 157 | LXC_get_version(PyObject *self, PyObject *args) |
b6adc92b SG |
158 | { |
159 | return PyUnicode_FromString(lxc_get_version()); | |
160 | } | |
161 | ||
be2e4e54 SG |
162 | // Container properties |
163 | static PyObject * | |
2ebec36f | 164 | Container_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 | ||
170 | static PyObject * | |
2ebec36f | 171 | Container_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 | ||
180 | static PyObject * | |
2ebec36f | 181 | Container_init_pid(Container *self, void *closure) |
be2e4e54 | 182 | { |
2ebec36f | 183 | return PyLong_FromLong(self->container->init_pid(self->container)); |
be2e4e54 SG |
184 | } |
185 | ||
186 | static PyObject * | |
2ebec36f | 187 | Container_name(Container *self, void *closure) |
be2e4e54 SG |
188 | { |
189 | return PyUnicode_FromString(self->container->name); | |
190 | } | |
191 | ||
192 | static PyObject * | |
2ebec36f | 193 | Container_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 | ||
202 | static PyObject * | |
2ebec36f | 203 | Container_state(Container *self, void *closure) |
be2e4e54 SG |
204 | { |
205 | return PyUnicode_FromString(self->container->state(self->container)); | |
206 | } | |
207 | ||
208 | // Container Functions | |
209 | static PyObject * | |
210 | Container_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 | ||
226 | static PyObject * | |
227 | Container_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 | ||
270 | static PyObject * | |
271 | Container_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 | ||
280 | static PyObject * | |
281 | Container_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 |
290 | static PyObject * |
291 | Container_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 |
325 | static PyObject * |
326 | Container_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 |
360 | static PyObject * |
361 | Container_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 |
367 | static PyObject * |
368 | Container_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 |
402 | static PyObject * |
403 | Container_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 |
457 | static PyObject * |
458 | Container_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 | ||
482 | static PyObject * | |
483 | Container_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 |
507 | static PyObject * |
508 | Container_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 |
525 | static PyObject * |
526 | Container_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 |
543 | static PyObject * |
544 | Container_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 |
560 | static PyObject * |
561 | Container_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 | ||
577 | static PyObject * | |
578 | Container_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 | ||
620 | static PyObject * | |
621 | Container_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 | ||
630 | static PyObject * | |
631 | Container_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 |
640 | static PyObject * |
641 | Container_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 | ||
658 | static PyObject * | |
659 | Container_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 |
674 | static PyObject * |
675 | Container_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 | ||
692 | static 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 | ||
720 | static 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 | ||
856 | static PyTypeObject _lxc_ContainerType = { | |
857 | PyVarObject_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 | 898 | static 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 |
906 | static PyModuleDef _lxcmodule = { |
907 | PyModuleDef_HEAD_INIT, | |
908 | "_lxc", | |
909 | "Binding for liblxc in python", | |
910 | -1, | |
24fcdb39 | 911 | LXC_methods |
be2e4e54 SG |
912 | }; |
913 | ||
914 | PyMODINIT_FUNC | |
915 | PyInit__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 | } |