]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/pythondir.c
77245b07dbb31f8279d8fe7459848f08b81b7b94
[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 /*
12    Copyright (C) 2004-2005 Kern Sibbald
13
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License as
16    published by the Free Software Foundation; either version 2 of
17    the License, or (at your option) any later version.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22    General Public License for more details.
23
24    You should have received a copy of the GNU General Public
25    License along with this program; if not, write to the Free
26    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27    MA 02111-1307, USA.
28
29  */
30
31 #include "bacula.h"
32 #include "dird.h"
33
34 #ifdef HAVE_PYTHON
35 #undef _POSIX_C_SOURCE
36 #include <Python.h>
37
38 extern JCR *get_jcr_from_PyObject(PyObject *self);
39 extern PyObject *find_method(PyObject *eventsObject, PyObject *method, 
40          const char *name);
41
42
43 static PyObject *set_job_events(PyObject *self, PyObject *arg);
44 static PyObject *job_run(PyObject *self, PyObject *arg);
45 static PyObject *job_write(PyObject *self, PyObject *arg);
46 static PyObject *job_cancel(PyObject *self, PyObject *arg);
47
48 PyMethodDef JobMethods[] = {
49     {"set_events", set_job_events, METH_VARARGS, "Set Job events"},
50     {"run", job_run, METH_VARARGS, "Run a Job"},
51     {"write", job_write, METH_VARARGS, "Write to output"},
52     {"cancel", job_cancel, METH_VARARGS, "Cancel a Job"},
53     {NULL, NULL, 0, NULL}             /* last item */
54 };
55  
56
57 struct s_vars {
58    const char *name;
59    char *fmt;
60 };
61
62 /* Read-only variables */
63 static struct s_vars getvars[] = {
64    { N_("Job"),        "s"},
65    { N_("DirName"),    "s"},
66    { N_("Level"),      "s"},
67    { N_("Type"),       "s"},
68    { N_("JobId"),      "i"},
69    { N_("Client"),     "s"},
70    { N_("NumVols"),    "i"},
71    { N_("Pool"),       "s"},
72    { N_("Storage"),    "s"},
73    { N_("Catalog"),    "s"},
74    { N_("MediaType"),  "s"},
75    { N_("JobName"),    "s"},
76    { N_("JobStatus"),  "s"},
77    { N_("Priority"),   "i"},
78
79    { NULL,             NULL}
80 };
81
82 /* Writable variables */
83 static struct s_vars setvars[] = {
84    { N_("JobReport"),   "s"},
85    { N_("VolumeName"),  "s"},
86    { N_("Priority"),    "i"},
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:                            /* Director's name */
124       return Py_BuildValue(getvars[i].fmt, my_name);
125    case 2:                            /* level */
126       return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
127    case 3:                            /* type */
128       return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
129    case 4:                            /* JobId */
130       return Py_BuildValue(getvars[i].fmt, jcr->JobId);
131    case 5:                            /* Client */
132       return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
133    case 6:                            /* NumVols */
134       return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
135    case 7:                            /* Pool */
136       return Py_BuildValue(getvars[i].fmt, jcr->pool->hdr.name);
137    case 8:                            /* Storage */
138       return Py_BuildValue(getvars[i].fmt, jcr->store->hdr.name);
139    case 9:
140       return Py_BuildValue(getvars[i].fmt, jcr->catalog->hdr.name);
141    case 10:                           /* MediaType */
142       return Py_BuildValue(getvars[i].fmt, jcr->store->media_type);
143    case 11:                           /* JobName */
144       return Py_BuildValue(getvars[i].fmt, jcr->Job);
145    case 12:                           /* JobStatus */
146       buf[1] = 0;
147       buf[0] = jcr->JobStatus;
148       return Py_BuildValue(getvars[i].fmt, buf);
149    case 13:                           /* Priority */
150       return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
151    }
152    bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname);
153 bail_out:
154    PyErr_SetString(PyExc_AttributeError, errmsg);
155    return NULL;
156 }
157
158
159 /* Set Job variables */
160 /*  Returns:   0 for OK
161  *            -1 for error
162  */
163 int job_setattr(PyObject *self, char *attrname, PyObject *value)
164 {
165    JCR *jcr;
166    bool found = false;
167    char *strval = NULL;
168    int intval = 0;
169    int i;
170
171    Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
172    if (value == NULL) {                /* Cannot delete variables */
173        goto bail_out;
174    }
175    jcr = get_jcr_from_PyObject(self);
176    if (!jcr) {
177       goto bail_out;
178    }
179
180    /* Find attribute name in list */
181    for (i=0; setvars[i].name; i++) {
182       if (strcmp(setvars[i].name, attrname) == 0) {
183          found = true;
184          break;
185       }
186    }
187    if (!found) {
188       goto bail_out;
189    }
190    /* Get argument value */
191    if (setvars[i].fmt != NULL) {
192       switch (setvars[i].fmt[0]) {
193       case 's':
194          if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
195             PyErr_SetString(PyExc_TypeError, "Read-only attribute");
196             return -1;
197          }
198          break;
199       case 'i':
200          if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
201             PyErr_SetString(PyExc_TypeError, "Read-only attribute");
202             return -1;
203          }
204          break;
205       }
206    }   
207    switch (i) {
208    case 0:                            /* JobReport */
209       Jmsg(jcr, M_INFO, 0, "%s", strval);
210       return 0;
211    case 1:                            /* VolumeName */
212       /* Make sure VolumeName is valid and we are in VolumeName event */
213       if (strcmp("NewVolume", jcr->event) == 0 &&
214           is_volume_name_legal(NULL, strval)) {
215          pm_strcpy(jcr->VolumeName, strval);
216          Dmsg1(100, "Set Vol=%s\n", strval);
217          return 0;
218       } else {
219          jcr->VolumeName[0] = 0;
220       }
221       break;
222    case 2:                            /* Priority */
223       Dmsg1(000, "Set priority=%d\n", intval);
224       return 0;
225    }
226 bail_out:
227    PyErr_SetString(PyExc_AttributeError, attrname);
228    return -1;
229 }
230
231
232 static PyObject *set_job_events(PyObject *self, PyObject *arg)
233 {
234    PyObject *eObject;
235    JCR *jcr;
236
237    Dmsg0(100, "In set_job_events.\n");
238    if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
239       Dmsg0(000, "Error in ParseTuple\n");
240       return NULL;
241    }
242    jcr = get_jcr_from_PyObject(self);
243    Py_XDECREF((PyObject *)jcr->Python_events);
244    Py_INCREF(eObject);
245    jcr->Python_events = (void *)eObject;
246    Py_INCREF(Py_None);
247    return Py_None;
248 }
249
250 /* Run a Bacula command */
251 static PyObject *job_run(PyObject *self, PyObject *arg)
252 {
253    JCR *jcr;
254    char *item;
255    int stat;
256
257    if (!PyArg_ParseTuple(arg, "s:run", &item)) {
258       Dmsg0(000, "Error in ParseTuple\n");
259       return NULL;
260    }
261    /* Release lock due to recursion */
262    PyEval_ReleaseLock();
263    jcr = get_jcr_from_PyObject(self);
264    UAContext *ua = new_ua_context(jcr);
265    ua->batch = true;
266    pm_strcpy(ua->cmd, item);          /* copy command */
267    parse_ua_args(ua);                 /* parse command */
268    stat = run_cmd(ua, ua->cmd);
269    free_ua_context(ua);
270    PyEval_AcquireLock();
271    return PyInt_FromLong((long)stat);
272 }
273
274 static PyObject *job_write(PyObject *self, PyObject *args)
275 {
276    char *text = NULL;
277
278    if (!PyArg_ParseTuple(args, "s:write", &text)) {
279       Dmsg0(000, "Parse tuple error in job_write\n");
280       return NULL;
281    }
282    if (text) {
283       Jmsg(NULL, M_INFO, 0, "%s", text);
284    }
285    Py_INCREF(Py_None);
286    return Py_None;
287 }
288
289 static PyObject *job_cancel(PyObject *self, PyObject *args)
290 {
291    JobId_t JobId = 0;
292    JCR *jcr;
293    bool found = false;
294
295    if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
296       Dmsg0(000, "Parse tuple error in job_write\n");
297       return NULL;
298    }
299    lock_jcr_chain();
300    foreach_jcr(jcr) {
301       if (jcr->JobId == 0) {
302          free_locked_jcr(jcr);           /* OK to free now cuz chain is locked */
303          continue;
304       }
305       if (jcr->JobId == JobId) {
306          found = true;
307          break;
308       }
309    }
310    if (!found) {
311       unlock_jcr_chain();
312       /* ***FIXME*** raise exception */
313       return NULL;
314    }
315    unlock_jcr_chain();
316    PyEval_ReleaseLock();
317    UAContext *ua = new_ua_context(jcr);
318    ua->batch = true;
319    if (!cancel_job(ua, jcr)) {
320       /* ***FIXME*** raise exception */
321       return NULL;
322    }
323    free_ua_context(ua);
324    free_locked_jcr(jcr);
325    PyEval_AcquireLock();   
326    Py_INCREF(Py_None);
327    return Py_None;
328 }
329
330 /*
331  * Generate a Job event, which means look up the event
332  *  method defined by the user, and if it exists, 
333  *  call it.
334  */
335 int generate_job_event(JCR *jcr, const char *event)
336 {
337    PyObject *method = NULL;
338    PyObject *Job = (PyObject *)jcr->Python_job;
339    PyObject *events = (PyObject *)jcr->Python_events;
340    PyObject *result = NULL;
341    int stat = 0;
342
343    if (!Job || !events) {
344       return 0;
345    }
346
347    PyEval_AcquireLock();
348
349    method = find_method(events, method, event);
350    if (!method) {
351       goto bail_out;
352    }
353
354    bstrncpy(jcr->event, event, sizeof(jcr->event));
355    result = PyObject_CallFunction(method, "O", Job);
356    jcr->event[0] = 0;             /* no event in progress */
357    if (result == NULL) {
358       if (PyErr_Occurred()) {
359          PyErr_Print();
360          Dmsg1(000, "Error in Python method %s\n", event);
361       }
362    } else {
363       stat = 1;
364    }
365    Py_XDECREF(result);
366
367 bail_out:
368    PyEval_ReleaseLock();
369    return stat;
370 }
371
372 bool python_set_prog(JCR*, char const*) { return false; }
373
374 #else
375
376 /* Dummy if Python not configured */
377 int generate_job_event(JCR *jcr, const char *event) { return 1; }
378    
379
380 #endif /* HAVE_PYTHON */