3 * Bacula interface to Python for the Director
5 * Kern Sibbald, November MMIV
12 Copyright (C) 2004-2005 Kern Sibbald
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.
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.
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,
35 #undef _POSIX_C_SOURCE
38 extern JCR *get_jcr_from_PyObject(PyObject *self);
39 extern PyObject *find_method(PyObject *eventsObject, PyObject *method,
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);
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 */
62 /* Read-only variables */
63 static struct s_vars getvars[] = {
65 { N_("DirName"), "s"},
70 { N_("NumVols"), "i"},
72 { N_("Storage"), "s"},
73 { N_("Catalog"), "s"},
74 { N_("MediaType"), "s"},
75 { N_("JobName"), "s"},
76 { N_("JobStatus"), "s"},
77 { N_("Priority"), "i"},
82 /* Writable variables */
83 static struct s_vars setvars[] = {
84 { N_("JobReport"), "s"},
85 { N_("VolumeName"), "s"},
86 { N_("Priority"), "i"},
92 /* Return Job variables */
93 /* Returns: NULL if error
94 * PyObject * return value if OK
96 PyObject *job_getattr(PyObject *self, char *attrname)
104 Dmsg0(100, "In job_getattr.\n");
105 jcr = get_jcr_from_PyObject(self);
107 bstrncpy(errmsg, "Job pointer not found.", sizeof(errmsg));
110 for (i=0; getvars[i].name; i++) {
111 if (strcmp(getvars[i].name, attrname) == 0) {
117 /* Try our methods */
118 return Py_FindMethod(JobMethods, self, attrname);
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);
126 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
128 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
130 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
132 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
133 case 6: /* NumVols */
134 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
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);
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 */
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);
152 bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname);
154 PyErr_SetString(PyExc_AttributeError, errmsg);
159 /* Set Job variables */
163 int job_setattr(PyObject *self, char *attrname, PyObject *value)
171 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
172 if (value == NULL) { /* Cannot delete variables */
175 jcr = get_jcr_from_PyObject(self);
180 /* Find attribute name in list */
181 for (i=0; setvars[i].name; i++) {
182 if (strcmp(setvars[i].name, attrname) == 0) {
190 /* Get argument value */
191 if (setvars[i].fmt != NULL) {
192 switch (setvars[i].fmt[0]) {
194 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
195 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
200 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
201 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
208 case 0: /* JobReport */
209 Jmsg(jcr, M_INFO, 0, "%s", strval);
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);
219 jcr->VolumeName[0] = 0;
222 case 2: /* Priority */
223 Dmsg1(000, "Set priority=%d\n", intval);
227 PyErr_SetString(PyExc_AttributeError, attrname);
232 static PyObject *set_job_events(PyObject *self, PyObject *arg)
237 Dmsg0(100, "In set_job_events.\n");
238 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
239 Dmsg0(000, "Error in ParseTuple\n");
242 jcr = get_jcr_from_PyObject(self);
243 Py_XDECREF((PyObject *)jcr->Python_events);
245 jcr->Python_events = (void *)eObject;
250 /* Run a Bacula command */
251 static PyObject *job_run(PyObject *self, PyObject *arg)
257 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
258 Dmsg0(000, "Error in ParseTuple\n");
261 /* Release lock due to recursion */
262 PyEval_ReleaseLock();
263 jcr = get_jcr_from_PyObject(self);
264 UAContext *ua = new_ua_context(jcr);
266 pm_strcpy(ua->cmd, item); /* copy command */
267 parse_ua_args(ua); /* parse command */
268 stat = run_cmd(ua, ua->cmd);
270 PyEval_AcquireLock();
271 return PyInt_FromLong((long)stat);
274 static PyObject *job_write(PyObject *self, PyObject *args)
278 if (!PyArg_ParseTuple(args, "s:write", &text)) {
279 Dmsg0(000, "Parse tuple error in job_write\n");
283 Jmsg(NULL, M_INFO, 0, "%s", text);
289 static PyObject *job_cancel(PyObject *self, PyObject *args)
295 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
296 Dmsg0(000, "Parse tuple error in job_write\n");
301 if (jcr->JobId == 0) {
302 free_locked_jcr(jcr); /* OK to free now cuz chain is locked */
305 if (jcr->JobId == JobId) {
312 /* ***FIXME*** raise exception */
316 PyEval_ReleaseLock();
317 UAContext *ua = new_ua_context(jcr);
319 if (!cancel_job(ua, jcr)) {
320 /* ***FIXME*** raise exception */
324 free_locked_jcr(jcr);
325 PyEval_AcquireLock();
331 * Generate a Job event, which means look up the event
332 * method defined by the user, and if it exists,
335 int generate_job_event(JCR *jcr, const char *event)
337 PyObject *method = NULL;
338 PyObject *Job = (PyObject *)jcr->Python_job;
339 PyObject *events = (PyObject *)jcr->Python_events;
340 PyObject *result = NULL;
343 if (!Job || !events) {
347 PyEval_AcquireLock();
349 method = find_method(events, method, event);
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()) {
360 Dmsg1(000, "Error in Python method %s\n", event);
368 PyEval_ReleaseLock();
372 bool python_set_prog(JCR*, char const*) { return false; }
376 /* Dummy if Python not configured */
377 int generate_job_event(JCR *jcr, const char *event) { return 1; }
380 #endif /* HAVE_PYTHON */