]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/pythondir.c
233f1f9ff808173e2e7506c37c84b6afb8d175fe
[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    { "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 static PyObject *set_job_events(PyObject *self, PyObject *arg)
247 {
248    PyObject *eObject;
249    JCR *jcr;
250
251    Dmsg0(100, "In set_job_events.\n");
252    if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
253       Dmsg0(000, "Error in ParseTuple\n");
254       return NULL;
255    }
256    jcr = get_jcr_from_PyObject(self);
257    Py_XDECREF((PyObject *)jcr->Python_events);
258    Py_INCREF(eObject);
259    jcr->Python_events = (void *)eObject;
260    Py_INCREF(Py_None);
261    return Py_None;
262 }
263
264 /* Run a Bacula command */
265 static PyObject *job_run(PyObject *self, PyObject *arg)
266 {
267    JCR *jcr;
268    char *item;
269    int stat;
270
271    if (!PyArg_ParseTuple(arg, "s:run", &item)) {
272       Dmsg0(000, "Error in ParseTuple\n");
273       return NULL;
274    }
275    /* Release lock due to recursion */
276    PyEval_ReleaseLock();
277    jcr = get_jcr_from_PyObject(self);
278    UAContext *ua = new_ua_context(jcr);
279    ua->batch = true;
280    pm_strcpy(ua->cmd, item);          /* copy command */
281    parse_ua_args(ua);                 /* parse command */
282    stat = run_cmd(ua, ua->cmd);
283    free_ua_context(ua);
284    PyEval_AcquireLock();
285    return PyInt_FromLong((long)stat);
286 }
287
288 static PyObject *job_write(PyObject *self, PyObject *args)
289 {
290    char *text = NULL;
291
292    if (!PyArg_ParseTuple(args, "s:write", &text)) {
293       Dmsg0(000, "Parse tuple error in job_write\n");
294       return NULL;
295    }
296    if (text) {
297       JCR *jcr = get_jcr_from_PyObject(self);
298       Jmsg(jcr, M_INFO, 0, "%s", text);
299    }
300    Py_INCREF(Py_None);
301    return Py_None;
302 }
303
304 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
305 {
306    char *VolName = NULL;
307
308    if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
309       Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
310       return NULL;
311    }
312    if (VolName) {
313       MEDIA_DBR mr;
314       int ok;
315       JCR *jcr = get_jcr_from_PyObject(self);
316       memset(&mr, 0, sizeof(mr));
317       bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
318       ok = db_get_media_record(jcr, jcr->db, &mr);
319       return Py_BuildValue("i", ok);
320    }
321    Py_INCREF(Py_None);
322    return Py_None;
323 }
324
325
326 static PyObject *job_cancel(PyObject *self, PyObject *args)
327 {
328    JobId_t JobId = 0;
329    JCR *jcr;
330    bool found = false;
331
332    if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
333       Dmsg0(000, "Parse tuple error in job_write\n");
334       return NULL;
335    }
336    foreach_jcr(jcr) {
337       if (jcr->JobId == 0) {
338          free_jcr(jcr);
339          continue;
340       }
341       if (jcr->JobId == JobId) {
342          found = true;
343          break;
344       }
345    }
346    if (!found) {
347       /* ***FIXME*** raise exception */
348       return NULL;
349    }
350    PyEval_ReleaseLock();
351    UAContext *ua = new_ua_context(jcr);
352    ua->batch = true;
353    if (!cancel_job(ua, jcr)) {
354       /* ***FIXME*** raise exception */
355       return NULL;
356    }
357    free_ua_context(ua);
358    free_jcr(jcr);
359    PyEval_AcquireLock();   
360    Py_INCREF(Py_None);
361    return Py_None;
362 }
363
364 /*
365  * Generate a Job event, which means look up the event
366  *  method defined by the user, and if it exists, 
367  *  call it.
368  */
369 int generate_job_event(JCR *jcr, const char *event)
370 {
371    PyObject *method = NULL;
372    PyObject *Job = (PyObject *)jcr->Python_job;
373    PyObject *events = (PyObject *)jcr->Python_events;
374    PyObject *result = NULL;
375    int stat = 0;
376
377    if (!Job || !events) {
378       return 0;
379    }
380
381    PyEval_AcquireLock();
382
383    method = find_method(events, method, event);
384    if (!method) {
385       goto bail_out;
386    }
387
388    bstrncpy(jcr->event, event, sizeof(jcr->event));
389    result = PyObject_CallFunction(method, "O", Job);
390    jcr->event[0] = 0;             /* no event in progress */
391    if (result == NULL) {
392       if (PyErr_Occurred()) {
393          PyErr_Print();
394          Dmsg1(000, "Error in Python method %s\n", event);
395       }
396    } else {
397       stat = 1;
398    }
399    Py_XDECREF(result);
400
401 bail_out:
402    PyEval_ReleaseLock();
403    return stat;
404 }
405
406 bool python_set_prog(JCR*, char const*) { return false; }
407
408 #else
409
410 /* Dummy if Python not configured */
411 int generate_job_event(JCR *jcr, const char *event) { return 1; }
412    
413
414 #endif /* HAVE_PYTHON */