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