6b1284c404b25816c7555258540ae5faa8671734
[util-vserver.git] / python / vserverimpl.c
1 /* Copyright 2005 Princeton University
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions
5 are met: 
6
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9       
10     * Redistributions in binary form must reproduce the above
11       copyright notice, this list of conditions and the following
12       disclaimer in the documentation and/or other materials provided
13       with the distribution.
14       
15     * Neither the name of the copyright holder nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18       
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PRINCETON
23 UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29 WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE. 
31
32 */
33
34 #include <Python.h>
35
36 #include <errno.h>
37 #include <stdint.h>
38 #include <unistd.h>
39
40 #include "config.h"
41 #include "pathconfig.h"
42 #include "planetlab.h"
43 #include "virtual.h"
44 #include "vserver.h"
45 #include "vserver-internal.h"
46
47 static int
48 get_rspec(PyObject *resources, rspec_t *rspec)
49 {
50   PyObject  *cpu_share;
51
52   if (!PyMapping_Check(resources))
53     {
54       PyErr_SetString(PyExc_TypeError, "invalid rspec");
55       return -1;
56     }
57   if ((cpu_share = PyMapping_GetItemString(resources, "nm_cpu_share")))
58     {
59       if (PyInt_Check(cpu_share))
60         {
61           rspec->cpu_share = PyInt_AS_LONG(cpu_share);
62           return 0;
63         }
64       PyErr_SetString(PyExc_TypeError, "nm_cpu_share not an integer");
65     }
66
67   return -1;
68 }
69
70 /*
71  * context create
72  */
73 static PyObject *
74 vserver_chcontext(PyObject *self, PyObject *args)
75 {
76   xid_t  ctx;
77   uint32_t  flags = 0;
78   uint32_t  bcaps = ~vc_get_insecurebcaps();
79   rspec_t  rspec = { 32, VC_VXF_SCHED_FLAGS, -1, -1 };
80   PyObject  *resources;
81
82   if (!PyArg_ParseTuple(args, "IO|K", &ctx, &resources, &flags) ||
83       get_rspec(resources, &rspec))
84     return NULL;
85
86   if (pl_chcontext(ctx, flags, bcaps, &rspec))
87     return PyErr_SetFromErrno(PyExc_OSError);
88
89   return Py_None;
90 }
91
92 static PyObject *
93 vserver_set_rlimit(PyObject *self, PyObject *args) {
94         struct vc_rlimit limits;
95         xid_t xid;
96         int resource;
97         PyObject *ret;
98
99         limits.min = VC_LIM_KEEP;
100         limits.soft = VC_LIM_KEEP;
101         limits.hard = VC_LIM_KEEP;
102
103         if (!PyArg_ParseTuple(args, "IiL", &xid, &resource, &limits.hard))
104                 return NULL;
105
106         ret = Py_None;
107         if (vc_set_rlimit(xid, resource, &limits)) 
108                 ret = PyErr_SetFromErrno(PyExc_OSError);
109         else if (vc_get_rlimit(xid, resource, &limits)==-1)
110                 ret = PyErr_SetFromErrno(PyExc_OSError);
111         else
112                 ret = Py_BuildValue("L",limits.hard);
113
114         return ret;
115 }
116
117 static PyObject *
118 vserver_get_rlimit(PyObject *self, PyObject *args) {
119         struct vc_rlimit limits;
120         xid_t xid;
121         int resource;
122         PyObject *ret;
123
124         limits.min = VC_LIM_KEEP;
125         limits.soft = VC_LIM_KEEP;
126         limits.hard = VC_LIM_KEEP;
127
128         if (!PyArg_ParseTuple(args, "Ii", &xid, &resource))
129                 return NULL;
130
131         ret = Py_None;
132         if (vc_get_rlimit(xid, resource, &limits)==-1)
133                 ret = PyErr_SetFromErrno(PyExc_OSError);
134         else
135                 ret = Py_BuildValue("L",limits.hard);
136
137         return ret;
138 }
139
140 /*
141  * setsched
142  */
143 static PyObject *
144 vserver_setsched(PyObject *self, PyObject *args)
145 {
146   xid_t  ctx;
147   rspec_t  rspec = { 32, VC_VXF_SCHED_FLAGS, -1, -1 };
148   PyObject  *resources;
149
150   if (!PyArg_ParseTuple(args, "IO", &ctx, &resources) ||
151       get_rspec(resources, &rspec))
152     return NULL;
153
154   /* ESRCH indicates that there are no processes in the context */
155   if (pl_setsched(ctx, rspec.cpu_share, rspec.cpu_sched_flags) &&
156       errno != ESRCH)
157     return PyErr_SetFromErrno(PyExc_OSError);
158
159   return Py_None;
160 }
161
162 static PyObject *
163 vserver_get_dlimit(PyObject *self, PyObject *args)
164 {
165         PyObject *res;
166         char* path;
167         unsigned xid;
168         struct vcmd_ctx_dlimit_v0 data;
169         int r;
170
171         if (!PyArg_ParseTuple(args, "si", &path,&xid))
172                 return NULL;
173
174         memset(&data, 0, sizeof(data));
175         data.name = path;
176         data.flags = 0;
177         r = vserver(VCMD_get_dlimit, xid, &data);
178         if (r>=0) {
179                 res = Py_BuildValue("(i,i,i,i,i)",
180                                     data.space_used,
181                                     data.space_total,
182                                     data.inodes_used,
183                                     data.inodes_total,
184                                     data.reserved);
185         } else {
186                 res = PyErr_SetFromErrno(PyExc_OSError);
187         }
188
189         return res;
190 }
191
192
193 static PyObject *
194 vserver_set_dlimit(PyObject *self, PyObject *args)
195 {
196         char* path;
197         unsigned xid;
198         struct vcmd_ctx_dlimit_base_v0 init;
199         struct vcmd_ctx_dlimit_v0 data;
200
201         memset(&data,0,sizeof(data));
202         if (!PyArg_ParseTuple(args, "siiiiii", &path,
203                               &xid,
204                               &data.space_used,
205                               &data.space_total,
206                               &data.inodes_used,
207                               &data.inodes_total,
208                               &data.reserved))
209                 return NULL;
210
211         data.name = path;
212         data.flags = 0;
213
214         memset(&init, 0, sizeof(init));
215         init.name = path;
216         init.flags = 0;
217
218         if ((vserver(VCMD_add_dlimit, xid, &init) && errno != EEXIST) ||
219             vserver(VCMD_set_dlimit, xid, &data))
220           return PyErr_SetFromErrno(PyExc_OSError);
221
222         return Py_None; 
223 }
224
225 static PyObject *
226 vserver_unset_dlimit(PyObject *self, PyObject *args)
227 {
228   char  *path;
229   unsigned  xid;
230   struct vcmd_ctx_dlimit_base_v0  init;
231
232   if (!PyArg_ParseTuple(args, "si", &path, &xid))
233     return NULL;
234
235   memset(&init, 0, sizeof(init));
236   init.name = path;
237   init.flags = 0;
238
239   if (vserver(VCMD_rem_dlimit, xid, &init) && errno != ESRCH)
240     return PyErr_SetFromErrno(PyExc_OSError);
241
242   return Py_None;       
243 }
244
245 static PyObject *
246 vserver_killall(PyObject *self, PyObject *args)
247 {
248   xid_t  ctx;
249   int  sig;
250
251   if (!PyArg_ParseTuple(args, "Ii", &ctx, &sig))
252     return NULL;
253
254   if (vc_ctx_kill(ctx, 0, sig) && errno != ESRCH)
255     return PyErr_SetFromErrno(PyExc_OSError);
256
257   return Py_None;
258 }
259
260 static PyMethodDef  methods[] = {
261   { "chcontext", vserver_chcontext, METH_VARARGS,
262     "chcontext to vserver with provided flags" },
263   { "setsched", vserver_setsched, METH_VARARGS,
264     "Change vserver scheduling attributes for given vserver context" },
265   { "setdlimit", vserver_set_dlimit, METH_VARARGS,
266     "Set disk limits for given vserver context" },
267   { "unsetdlimit", vserver_unset_dlimit, METH_VARARGS,
268     "Remove disk limits for given vserver context" },
269   { "getdlimit", vserver_get_dlimit, METH_VARARGS,
270     "Get disk limits for given vserver context" },
271   { "setrlimit", vserver_set_rlimit, METH_VARARGS,
272     "Set resource limits for given resource of a vserver context" },
273   { "getrlimit", vserver_get_rlimit, METH_VARARGS,
274     "Get resource limits for given resource of a vserver context" },
275   { "killall", vserver_killall, METH_VARARGS,
276     "Send signal to all processes in vserver context" },
277   { NULL, NULL, 0, NULL }
278 };
279
280 PyMODINIT_FUNC
281 initvserverimpl(void)
282 {
283   PyObject  *mod;
284
285   mod = Py_InitModule("vserverimpl", methods);
286
287   /* export the set of 'safe' capabilities */
288   PyModule_AddIntConstant(mod, "CAP_SAFE", ~vc_get_insecurebcaps());
289
290   /* export the default vserver directory */
291   PyModule_AddStringConstant(mod, "VSERVER_BASEDIR", DEFAULT_VSERVERDIR);
292
293   /* export limit-related constants */
294   PyModule_AddIntConstant(mod, "DLIMIT_KEEP", (int)CDLIM_KEEP);
295   PyModule_AddIntConstant(mod, "DLIMIT_INF", (int)CDLIM_INFINITY);
296 }