3 * Bacula interface to Python for the Director
5 * Kern Sibbald, November MMIV
11 Copyright (C) 2004-2006 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 amended 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 char *configfile;
33 extern JCR *get_jcr_from_PyObject(PyObject *self);
34 extern PyObject *find_method(PyObject *eventsObject, PyObject *method,
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);
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 */
59 /* Read-only variables */
60 static struct s_vars getvars[] = {
75 { "CatalogRes", "(sssssis)"},
80 /* Writable variables */
81 static struct s_vars setvars[] = {
90 /* Return Job variables */
91 /* Returns: NULL if error
92 * PyObject * return value if OK
94 PyObject *job_getattr(PyObject *self, char *attrname)
102 Dmsg0(100, "In job_getattr.\n");
103 jcr = get_jcr_from_PyObject(self);
105 bstrncpy(errmsg, _("Job pointer not found."), sizeof(errmsg));
108 for (i=0; getvars[i].name; i++) {
109 if (strcmp(getvars[i].name, attrname) == 0) {
115 /* Try our methods */
116 return Py_FindMethod(JobMethods, self, attrname);
120 return Py_BuildValue(getvars[i].fmt, jcr->job->hdr.name);
122 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
124 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
126 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
128 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
129 case 5: /* NumVols */
131 memset(&pr, 0, sizeof(pr));
132 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
133 if (db_get_pool_record(jcr, jcr->db, &pr)) {
134 jcr->NumVols = pr.NumVols;
135 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
137 bsnprintf(errmsg, sizeof(errmsg), _("Pool record not found."));
141 return Py_BuildValue(getvars[i].fmt, jcr->pool->hdr.name);
142 case 7: /* Storage */
143 return Py_BuildValue(getvars[i].fmt, jcr->store->hdr.name);
145 return Py_BuildValue(getvars[i].fmt, jcr->catalog->hdr.name);
146 case 9: /* MediaType */
147 return Py_BuildValue(getvars[i].fmt, jcr->store->media_type);
148 case 10: /* JobName */
149 return Py_BuildValue(getvars[i].fmt, jcr->Job);
150 case 11: /* JobStatus */
152 buf[0] = jcr->JobStatus;
153 return Py_BuildValue(getvars[i].fmt, buf);
154 case 12: /* Priority */
155 return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
157 return Py_BuildValue(getvars[i].fmt, jcr->VolumeName);
158 case 14: /* CatalogRes */
159 return Py_BuildValue(getvars[i].fmt,
160 jcr->catalog->db_name, jcr->catalog->db_address,
161 jcr->catalog->db_user, jcr->catalog->db_password,
162 jcr->catalog->db_socket, jcr->catalog->db_port,
166 bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
168 PyErr_SetString(PyExc_AttributeError, errmsg);
173 /* Set Job variables */
177 int job_setattr(PyObject *self, char *attrname, PyObject *value)
185 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
186 if (value == NULL) { /* Cannot delete variables */
189 jcr = get_jcr_from_PyObject(self);
194 /* Find attribute name in list */
195 for (i=0; setvars[i].name; i++) {
196 if (strcmp(setvars[i].name, attrname) == 0) {
204 /* Get argument value */
205 if (setvars[i].fmt != NULL) {
206 switch (setvars[i].fmt[0]) {
208 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
209 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
214 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
215 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
222 case 0: /* JobReport */
223 Jmsg(jcr, M_INFO, 0, "%s", strval);
225 case 1: /* VolumeName */
226 /* Make sure VolumeName is valid and we are in VolumeName event */
227 if (strcmp("NewVolume", jcr->event) == 0 &&
228 is_volume_name_legal(NULL, strval)) {
229 pm_strcpy(jcr->VolumeName, strval);
230 Dmsg1(100, "Set Vol=%s\n", strval);
233 jcr->VolumeName[0] = 0;
236 case 2: /* Priority */
237 Dmsg1(000, "Set priority=%d\n", intval);
241 PyErr_SetString(PyExc_AttributeError, attrname);
246 * Set pointer to instantiated events class
248 static PyObject *set_job_events(PyObject *self, PyObject *arg)
253 Dmsg0(100, "In set_job_events.\n");
254 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
255 Dmsg0(000, "Error in ParseTuple\n");
258 jcr = get_jcr_from_PyObject(self);
259 Py_XDECREF((PyObject *)jcr->Python_events);
261 jcr->Python_events = (void *)eObject;
266 /* Run a Bacula job */
267 static PyObject *job_run(PyObject *self, PyObject *arg)
273 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
274 Dmsg0(000, "Error in ParseTuple\n");
277 /* Release lock due to recursion */
278 PyEval_ReleaseLock();
279 jcr = get_jcr_from_PyObject(self);
280 UAContext *ua = new_ua_context(jcr);
282 pm_strcpy(ua->cmd, item); /* copy command */
283 parse_ua_args(ua); /* parse command */
284 stat = run_cmd(ua, ua->cmd);
286 PyEval_AcquireLock();
287 return PyInt_FromLong((long)stat);
290 static PyObject *job_write(PyObject *self, PyObject *args)
294 if (!PyArg_ParseTuple(args, "s:write", &text)) {
295 Dmsg0(000, "Parse tuple error in job_write\n");
299 JCR *jcr = get_jcr_from_PyObject(self);
300 Jmsg(jcr, M_INFO, 0, "%s", text);
306 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
308 char *VolName = NULL;
310 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
311 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
317 JCR *jcr = get_jcr_from_PyObject(self);
318 memset(&mr, 0, sizeof(mr));
319 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
320 ok = db_get_media_record(jcr, jcr->db, &mr);
321 return Py_BuildValue("i", ok);
328 static PyObject *job_cancel(PyObject *self, PyObject *args)
334 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
335 Dmsg0(000, "Parse tuple error in job_write\n");
339 if (jcr->JobId == 0) {
342 if (jcr->JobId == JobId) {
347 /* endeach_jcr(jcr) not needed because freed below */
350 /* ***FIXME*** raise exception */
353 PyEval_ReleaseLock();
354 UAContext *ua = new_ua_context(jcr);
356 if (!cancel_job(ua, jcr)) {
357 /* ***FIXME*** raise exception */
362 PyEval_AcquireLock();
368 * Generate a Job event, which means look up the event
369 * method defined by the user, and if it exists,
372 int generate_job_event(JCR *jcr, const char *event)
374 PyObject *method = NULL;
375 PyObject *Job = (PyObject *)jcr->Python_job;
376 PyObject *events = (PyObject *)jcr->Python_events;
377 PyObject *result = NULL;
380 if (!Job || !events) {
384 PyEval_AcquireLock();
386 method = find_method(events, method, event);
391 bstrncpy(jcr->event, event, sizeof(jcr->event));
392 result = PyObject_CallFunction(method, "O", Job);
393 jcr->event[0] = 0; /* no event in progress */
394 if (result == NULL) {
395 if (PyErr_Occurred()) {
397 Dmsg1(000, "Error in Python method %s\n", event);
405 PyEval_ReleaseLock();
409 bool python_set_prog(JCR*, char const*) { return false; }
413 /* Dummy if Python not configured */
414 int generate_job_event(JCR *jcr, const char *event) { return 1; }
417 #endif /* HAVE_PYTHON */