3 * Bacula interface to Python for the Director
5 * Kern Sibbald, November MMIV
11 Copyright (C) 2004-2005 Kern Sibbald
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.
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.
29 #undef _POSIX_C_SOURCE
32 extern JCR *get_jcr_from_PyObject(PyObject *self);
33 extern PyObject *find_method(PyObject *eventsObject, PyObject *method,
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);
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 */
56 /* Read-only variables */
57 static struct s_vars getvars[] = {
59 { N_("DirName"), "s"},
64 { N_("NumVols"), "i"},
66 { N_("Storage"), "s"},
67 { N_("Catalog"), "s"},
68 { N_("MediaType"), "s"},
69 { N_("JobName"), "s"},
70 { N_("JobStatus"), "s"},
71 { N_("Priority"), "i"},
76 /* Writable variables */
77 static struct s_vars setvars[] = {
78 { N_("JobReport"), "s"},
79 { N_("VolumeName"), "s"},
80 { N_("Priority"), "i"},
86 /* Return Job variables */
87 /* Returns: NULL if error
88 * PyObject * return value if OK
90 PyObject *job_getattr(PyObject *self, char *attrname)
98 Dmsg0(100, "In job_getattr.\n");
99 jcr = get_jcr_from_PyObject(self);
101 bstrncpy(errmsg, "Job pointer not found.", sizeof(errmsg));
104 for (i=0; getvars[i].name; i++) {
105 if (strcmp(getvars[i].name, attrname) == 0) {
111 /* Try our methods */
112 return Py_FindMethod(JobMethods, self, attrname);
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);
120 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
122 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
124 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
126 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
127 case 6: /* NumVols */
128 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
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);
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 */
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);
146 bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname);
148 PyErr_SetString(PyExc_AttributeError, errmsg);
153 /* Set Job variables */
157 int job_setattr(PyObject *self, char *attrname, PyObject *value)
165 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
166 if (value == NULL) { /* Cannot delete variables */
169 jcr = get_jcr_from_PyObject(self);
174 /* Find attribute name in list */
175 for (i=0; setvars[i].name; i++) {
176 if (strcmp(setvars[i].name, attrname) == 0) {
184 /* Get argument value */
185 if (setvars[i].fmt != NULL) {
186 switch (setvars[i].fmt[0]) {
188 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
189 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
194 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
195 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
202 case 0: /* JobReport */
203 Jmsg(jcr, M_INFO, 0, "%s", strval);
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);
213 jcr->VolumeName[0] = 0;
216 case 2: /* Priority */
217 Dmsg1(000, "Set priority=%d\n", intval);
221 PyErr_SetString(PyExc_AttributeError, attrname);
226 static PyObject *set_job_events(PyObject *self, PyObject *arg)
231 Dmsg0(100, "In set_job_events.\n");
232 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
233 Dmsg0(000, "Error in ParseTuple\n");
236 jcr = get_jcr_from_PyObject(self);
237 Py_XDECREF((PyObject *)jcr->Python_events);
239 jcr->Python_events = (void *)eObject;
244 /* Run a Bacula command */
245 static PyObject *job_run(PyObject *self, PyObject *arg)
251 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
252 Dmsg0(000, "Error in ParseTuple\n");
255 /* Release lock due to recursion */
256 PyEval_ReleaseLock();
257 jcr = get_jcr_from_PyObject(self);
258 UAContext *ua = new_ua_context(jcr);
260 pm_strcpy(ua->cmd, item); /* copy command */
261 parse_ua_args(ua); /* parse command */
262 stat = run_cmd(ua, ua->cmd);
264 PyEval_AcquireLock();
265 return PyInt_FromLong((long)stat);
268 static PyObject *job_write(PyObject *self, PyObject *args)
272 if (!PyArg_ParseTuple(args, "s:write", &text)) {
273 Dmsg0(000, "Parse tuple error in job_write\n");
277 Jmsg(NULL, M_INFO, 0, "%s", text);
283 static PyObject *job_cancel(PyObject *self, PyObject *args)
289 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
290 Dmsg0(000, "Parse tuple error in job_write\n");
294 if (jcr->JobId == 0) {
298 if (jcr->JobId == JobId) {
304 /* ***FIXME*** raise exception */
307 PyEval_ReleaseLock();
308 UAContext *ua = new_ua_context(jcr);
310 if (!cancel_job(ua, jcr)) {
311 /* ***FIXME*** raise exception */
316 PyEval_AcquireLock();
322 * Generate a Job event, which means look up the event
323 * method defined by the user, and if it exists,
326 int generate_job_event(JCR *jcr, const char *event)
328 PyObject *method = NULL;
329 PyObject *Job = (PyObject *)jcr->Python_job;
330 PyObject *events = (PyObject *)jcr->Python_events;
331 PyObject *result = NULL;
334 if (!Job || !events) {
338 PyEval_AcquireLock();
340 method = find_method(events, method, event);
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()) {
351 Dmsg1(000, "Error in Python method %s\n", event);
359 PyEval_ReleaseLock();
363 bool python_set_prog(JCR*, char const*) { return false; }
367 /* Dummy if Python not configured */
368 int generate_job_event(JCR *jcr, const char *event) { return 1; }
371 #endif /* HAVE_PYTHON */