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