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