]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/pythondir.c
Mark translatable strings in all source files.
[bacula/bacula] / bacula / src / dird / pythondir.c
1 /*
2  *
3  * Bacula interface to Python for the Director
4  *
5  * Kern Sibbald, November MMIV
6  *
7  *   Version $Id$
8  *
9  */
10 /*
11    Copyright (C) 2004-2005 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    version 2 as amended with additional clauses defined in the
16    file LICENSE in the main source directory.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"
26 #include "dird.h"
27
28 #ifdef HAVE_PYTHON
29 #undef _POSIX_C_SOURCE
30 #include <Python.h>
31
32 extern char *configfile;
33 extern JCR *get_jcr_from_PyObject(PyObject *self);
34 extern PyObject *find_method(PyObject *eventsObject, PyObject *method, 
35          const char *name);
36
37
38 static PyObject *set_job_events(PyObject *self, PyObject *arg);
39 static PyObject *job_run(PyObject *self, PyObject *arg);
40 static PyObject *job_write(PyObject *self, PyObject *arg);
41 static PyObject *job_cancel(PyObject *self, PyObject *arg);
42 static PyObject *job_does_vol_exist(PyObject *self, PyObject *arg);
43
44 PyMethodDef JobMethods[] = {
45     {"set_events", set_job_events, METH_VARARGS, "Set Job events"},
46     {"run", job_run, METH_VARARGS, "Run a Job"},
47     {"write", job_write, METH_VARARGS, "Write to output"},
48     {"cancel", job_cancel, METH_VARARGS, "Cancel a Job"},
49     {"DoesVolumeExist", job_does_vol_exist, METH_VARARGS, "Does Volume Exist"},
50     {NULL, NULL, 0, NULL}             /* last item */
51 };
52  
53
54 struct s_vars {
55    const char *name;
56    char *fmt;
57 };
58
59 /* Read-only variables */
60 static struct s_vars getvars[] = {
61    { N_("Job"),        "s"},
62    { N_("Level"),      "s"},
63    { N_("Type"),       "s"},
64    { N_("JobId"),      "i"},
65    { N_("Client"),     "s"},
66    { N_("NumVols"),    "i"},
67    { N_("Pool"),       "s"},
68    { N_("Storage"),    "s"},
69    { N_("Catalog"),    "s"},
70    { N_("MediaType"),  "s"},
71    { N_("JobName"),    "s"},
72    { N_("JobStatus"),  "s"},
73    { N_("Priority"),   "i"},
74    { N_("CatalogRes"), "(sssssis)"},
75
76    { NULL,             NULL}
77 };
78
79 /* Writable variables */
80 static struct s_vars setvars[] = {
81    { N_("JobReport"),   "s"},
82    { N_("VolumeName"),  "s"},
83    { N_("Priority"),    "i"},
84
85    { NULL,             NULL}
86 };
87
88
89 /* Return Job variables */
90 /* Returns:  NULL if error
91  *           PyObject * return value if OK
92  */
93 PyObject *job_getattr(PyObject *self, char *attrname)
94 {
95    JCR *jcr;
96    bool found = false;
97    int i;
98    char buf[10];
99    char errmsg[200];
100
101    Dmsg0(100, "In job_getattr.\n");
102    jcr = get_jcr_from_PyObject(self);
103    if (!jcr) {
104       bstrncpy(errmsg, _("Job pointer not found."), sizeof(errmsg));
105       goto bail_out;
106    }
107    for (i=0; getvars[i].name; i++) {
108       if (strcmp(getvars[i].name, attrname) == 0) {
109          found = true;
110          break;
111       }
112    }
113    if (!found) {
114       /* Try our methods */
115       return Py_FindMethod(JobMethods, self, attrname);
116    }
117    switch (i) {
118    case 0:                            /* Job */
119       return Py_BuildValue(getvars[i].fmt, jcr->job->hdr.name);
120    case 1:                            /* level */
121       return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
122    case 2:                            /* type */
123       return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
124    case 3:                            /* JobId */
125       return Py_BuildValue(getvars[i].fmt, jcr->JobId);
126    case 4:                            /* Client */
127       return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
128    case 5:                            /* NumVols */
129       POOL_DBR pr;
130       memset(&pr, 0, sizeof(pr));
131       bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
132       if (db_get_pool_record(jcr, jcr->db, &pr)) {
133          jcr->NumVols = pr.NumVols;
134          return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
135       } else {
136          bsnprintf(errmsg, sizeof(errmsg), _("Pool record not found."));
137          goto bail_out;
138       }
139    case 6:                            /* Pool */
140       return Py_BuildValue(getvars[i].fmt, jcr->pool->hdr.name);
141    case 7:                            /* Storage */
142       return Py_BuildValue(getvars[i].fmt, jcr->store->hdr.name);
143    case 8:
144       return Py_BuildValue(getvars[i].fmt, jcr->catalog->hdr.name);
145    case  9:                           /* MediaType */
146       return Py_BuildValue(getvars[i].fmt, jcr->store->media_type);
147    case 10:                           /* JobName */
148       return Py_BuildValue(getvars[i].fmt, jcr->Job);
149    case 11:                           /* JobStatus */
150       buf[1] = 0;
151       buf[0] = jcr->JobStatus;
152       return Py_BuildValue(getvars[i].fmt, buf);
153    case 12:                           /* Priority */
154       return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
155    case 13:                           /* CatalogRes */
156       return Py_BuildValue(getvars[i].fmt,
157          jcr->catalog->db_name, jcr->catalog->db_address, 
158          jcr->catalog->db_user, jcr->catalog->db_password,
159          jcr->catalog->db_socket, jcr->catalog->db_port,
160          catalog_db);
161
162    }
163    bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
164 bail_out:
165    PyErr_SetString(PyExc_AttributeError, errmsg);
166    return NULL;
167 }
168
169
170 /* Set Job variables */
171 /*  Returns:   0 for OK
172  *            -1 for error
173  */
174 int job_setattr(PyObject *self, char *attrname, PyObject *value)
175 {
176    JCR *jcr;
177    bool found = false;
178    char *strval = NULL;
179    int intval = 0;
180    int i;
181
182    Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
183    if (value == NULL) {                /* Cannot delete variables */
184        goto bail_out;
185    }
186    jcr = get_jcr_from_PyObject(self);
187    if (!jcr) {
188       goto bail_out;
189    }
190
191    /* Find attribute name in list */
192    for (i=0; setvars[i].name; i++) {
193       if (strcmp(setvars[i].name, attrname) == 0) {
194          found = true;
195          break;
196       }
197    }
198    if (!found) {
199       goto bail_out;
200    }
201    /* Get argument value */
202    if (setvars[i].fmt != NULL) {
203       switch (setvars[i].fmt[0]) {
204       case 's':
205          if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
206             PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
207             return -1;
208          }
209          break;
210       case 'i':
211          if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
212             PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
213             return -1;
214          }
215          break;
216       }
217    }   
218    switch (i) {
219    case 0:                            /* JobReport */
220       Jmsg(jcr, M_INFO, 0, "%s", strval);
221       return 0;
222    case 1:                            /* VolumeName */
223       /* Make sure VolumeName is valid and we are in VolumeName event */
224       if (strcmp("NewVolume", jcr->event) == 0 &&
225           is_volume_name_legal(NULL, strval)) {
226          pm_strcpy(jcr->VolumeName, strval);
227          Dmsg1(100, "Set Vol=%s\n", strval);
228          return 0;
229       } else {
230          jcr->VolumeName[0] = 0;
231       }
232       break;
233    case 2:                            /* Priority */
234       Dmsg1(000, "Set priority=%d\n", intval);
235       return 0;
236    }
237 bail_out:
238    PyErr_SetString(PyExc_AttributeError, attrname);
239    return -1;
240 }
241
242
243 static PyObject *set_job_events(PyObject *self, PyObject *arg)
244 {
245    PyObject *eObject;
246    JCR *jcr;
247
248    Dmsg0(100, "In set_job_events.\n");
249    if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
250       Dmsg0(000, "Error in ParseTuple\n");
251       return NULL;
252    }
253    jcr = get_jcr_from_PyObject(self);
254    Py_XDECREF((PyObject *)jcr->Python_events);
255    Py_INCREF(eObject);
256    jcr->Python_events = (void *)eObject;
257    Py_INCREF(Py_None);
258    return Py_None;
259 }
260
261 /* Run a Bacula command */
262 static PyObject *job_run(PyObject *self, PyObject *arg)
263 {
264    JCR *jcr;
265    char *item;
266    int stat;
267
268    if (!PyArg_ParseTuple(arg, "s:run", &item)) {
269       Dmsg0(000, "Error in ParseTuple\n");
270       return NULL;
271    }
272    /* Release lock due to recursion */
273    PyEval_ReleaseLock();
274    jcr = get_jcr_from_PyObject(self);
275    UAContext *ua = new_ua_context(jcr);
276    ua->batch = true;
277    pm_strcpy(ua->cmd, item);          /* copy command */
278    parse_ua_args(ua);                 /* parse command */
279    stat = run_cmd(ua, ua->cmd);
280    free_ua_context(ua);
281    PyEval_AcquireLock();
282    return PyInt_FromLong((long)stat);
283 }
284
285 static PyObject *job_write(PyObject *self, PyObject *args)
286 {
287    char *text = NULL;
288
289    if (!PyArg_ParseTuple(args, "s:write", &text)) {
290       Dmsg0(000, "Parse tuple error in job_write\n");
291       return NULL;
292    }
293    if (text) {
294       JCR *jcr = get_jcr_from_PyObject(self);
295       Jmsg(jcr, M_INFO, 0, "%s", text);
296    }
297    Py_INCREF(Py_None);
298    return Py_None;
299 }
300
301 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
302 {
303    char *VolName = NULL;
304
305    if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
306       Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
307       return NULL;
308    }
309    if (VolName) {
310       MEDIA_DBR mr;
311       int ok;
312       JCR *jcr = get_jcr_from_PyObject(self);
313       memset(&mr, 0, sizeof(mr));
314       bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
315       ok = db_get_media_record(jcr, jcr->db, &mr);
316       return Py_BuildValue("i", ok);
317    }
318    Py_INCREF(Py_None);
319    return Py_None;
320 }
321
322
323 static PyObject *job_cancel(PyObject *self, PyObject *args)
324 {
325    JobId_t JobId = 0;
326    JCR *jcr;
327    bool found = false;
328
329    if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
330       Dmsg0(000, "Parse tuple error in job_write\n");
331       return NULL;
332    }
333    foreach_jcr(jcr) {
334       if (jcr->JobId == 0) {
335          free_jcr(jcr);
336          continue;
337       }
338       if (jcr->JobId == JobId) {
339          found = true;
340          break;
341       }
342    }
343    if (!found) {
344       /* ***FIXME*** raise exception */
345       return NULL;
346    }
347    PyEval_ReleaseLock();
348    UAContext *ua = new_ua_context(jcr);
349    ua->batch = true;
350    if (!cancel_job(ua, jcr)) {
351       /* ***FIXME*** raise exception */
352       return NULL;
353    }
354    free_ua_context(ua);
355    free_jcr(jcr);
356    PyEval_AcquireLock();   
357    Py_INCREF(Py_None);
358    return Py_None;
359 }
360
361 /*
362  * Generate a Job event, which means look up the event
363  *  method defined by the user, and if it exists, 
364  *  call it.
365  */
366 int generate_job_event(JCR *jcr, const char *event)
367 {
368    PyObject *method = NULL;
369    PyObject *Job = (PyObject *)jcr->Python_job;
370    PyObject *events = (PyObject *)jcr->Python_events;
371    PyObject *result = NULL;
372    int stat = 0;
373
374    if (!Job || !events) {
375       return 0;
376    }
377
378    PyEval_AcquireLock();
379
380    method = find_method(events, method, event);
381    if (!method) {
382       goto bail_out;
383    }
384
385    bstrncpy(jcr->event, event, sizeof(jcr->event));
386    result = PyObject_CallFunction(method, "O", Job);
387    jcr->event[0] = 0;             /* no event in progress */
388    if (result == NULL) {
389       if (PyErr_Occurred()) {
390          PyErr_Print();
391          Dmsg1(000, "Error in Python method %s\n", event);
392       }
393    } else {
394       stat = 1;
395    }
396    Py_XDECREF(result);
397
398 bail_out:
399    PyEval_ReleaseLock();
400    return stat;
401 }
402
403 bool python_set_prog(JCR*, char const*) { return false; }
404
405 #else
406
407 /* Dummy if Python not configured */
408 int generate_job_event(JCR *jcr, const char *event) { return 1; }
409    
410
411 #endif /* HAVE_PYTHON */