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