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 struct s_jl joblevels[];
34 extern JCR *get_jcr_from_PyObject(PyObject *self);
35 extern PyObject *find_method(PyObject *eventsObject, PyObject *method,
39 static PyObject *set_job_events(PyObject *self, PyObject *arg);
40 static PyObject *job_run(PyObject *self, PyObject *arg);
41 static PyObject *job_write(PyObject *self, PyObject *arg);
42 static PyObject *job_cancel(PyObject *self, PyObject *arg);
43 static PyObject *job_does_vol_exist(PyObject *self, PyObject *arg);
45 PyMethodDef JobMethods[] = {
46 {"set_events", set_job_events, METH_VARARGS, "Set Job events"},
47 {"run", job_run, METH_VARARGS, "Run a Job"},
48 {"write", job_write, METH_VARARGS, "Write to output"},
49 {"cancel", job_cancel, METH_VARARGS, "Cancel a Job"},
50 {"DoesVolumeExist", job_does_vol_exist, METH_VARARGS, "Does Volume Exist"},
51 {NULL, NULL, 0, NULL} /* last item */
60 /* Read-only variables */
61 static struct s_vars getvars[] = {
76 { "CatalogRes", "(sssssis)"},
87 /* Writable variables */
88 static struct s_vars setvars[] = {
98 /* Return Job variables */
99 /* Returns: NULL if error
100 * PyObject * return value if OK
102 PyObject *job_getattr(PyObject *self, char *attrname)
110 Dmsg0(100, "In job_getattr.\n");
111 jcr = get_jcr_from_PyObject(self);
113 bstrncpy(errmsg, _("Job pointer not found."), sizeof(errmsg));
116 for (i=0; getvars[i].name; i++) {
117 if (strcmp(getvars[i].name, attrname) == 0) {
123 /* Try our methods */
124 return Py_FindMethod(JobMethods, self, attrname);
128 return Py_BuildValue(getvars[i].fmt, jcr->job->hdr.name);
130 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
132 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
134 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
136 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
137 case 5: /* NumVols */
139 memset(&pr, 0, sizeof(pr));
140 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
141 if (db_get_pool_record(jcr, jcr->db, &pr)) {
142 jcr->NumVols = pr.NumVols;
143 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
145 bsnprintf(errmsg, sizeof(errmsg), _("Pool record not found."));
149 return Py_BuildValue(getvars[i].fmt, jcr->pool->name());
150 case 7: /* Storage */
152 return Py_BuildValue(getvars[i].fmt, jcr->wstore->name());
153 } else if (jcr->rstore) {
154 return Py_BuildValue(getvars[i].fmt, jcr->rstore->name());
159 return Py_BuildValue(getvars[i].fmt, jcr->catalog->name());
160 case 9: /* MediaType */
162 return Py_BuildValue(getvars[i].fmt, jcr->wstore->media_type);
163 } else if (jcr->rstore) {
164 return Py_BuildValue(getvars[i].fmt, jcr->rstore->media_type);
168 case 10: /* JobName */
169 return Py_BuildValue(getvars[i].fmt, jcr->Job);
170 case 11: /* JobStatus */
172 buf[0] = jcr->JobStatus;
173 return Py_BuildValue(getvars[i].fmt, buf);
174 case 12: /* Priority */
175 return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
177 return Py_BuildValue(getvars[i].fmt, jcr->VolumeName);
178 case 14: /* CatalogRes */
179 return Py_BuildValue(getvars[i].fmt,
180 jcr->catalog->db_name, jcr->catalog->db_address,
181 jcr->catalog->db_user, jcr->catalog->db_password,
182 jcr->catalog->db_socket, jcr->catalog->db_port,
184 case 15: /* JobErrors */
185 return Py_BuildValue(getvars[i].fmt, jcr->JobErrors);
186 case 16: /* JobFiles */
187 return Py_BuildValue(getvars[i].fmt, jcr->JobFiles);
188 case 17: /* SDJobFiles */
189 return Py_BuildValue(getvars[i].fmt, jcr->SDJobFiles);
190 case 18: /* SDErrors */
191 return Py_BuildValue(getvars[i].fmt, jcr->SDErrors);
192 case 19: /* FDJobStatus */
194 buf[0] = jcr->FDJobStatus;
195 return Py_BuildValue(getvars[i].fmt, buf);
196 case 29: /* SDJobStatus */
198 buf[0] = jcr->SDJobStatus;
199 return Py_BuildValue(getvars[i].fmt, buf);
201 bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
203 PyErr_SetString(PyExc_AttributeError, errmsg);
208 /* Set Job variables */
212 int job_setattr(PyObject *self, char *attrname, PyObject *value)
220 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
221 if (value == NULL) { /* Cannot delete variables */
224 jcr = get_jcr_from_PyObject(self);
229 /* Find attribute name in list */
230 for (i=0; setvars[i].name; i++) {
231 if (strcmp(setvars[i].name, attrname) == 0) {
239 /* Get argument value */
240 if (setvars[i].fmt != NULL) {
241 switch (setvars[i].fmt[0]) {
243 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
244 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
249 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
250 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
257 case 0: /* JobReport */
258 Jmsg(jcr, M_INFO, 0, "%s", strval);
260 case 1: /* VolumeName */
261 /* Make sure VolumeName is valid and we are in VolumeName event */
262 if (strcmp("NewVolume", jcr->event) == 0 &&
263 is_volume_name_legal(NULL, strval)) {
264 pm_strcpy(jcr->VolumeName, strval);
265 Dmsg1(100, "Set Vol=%s\n", strval);
268 jcr->VolumeName[0] = 0;
271 case 2: /* Priority */
272 Dmsg1(000, "Set priority=%d\n", intval);
273 if (intval >= 1 && intval <= 100) {
274 jcr->JobPriority = intval;
276 PyErr_SetString(PyExc_ValueError, _("Priority must be 1-100"));
279 case 3: /* Job Level */
280 if (strcmp("JobInit", jcr->event) != 0) {
281 PyErr_SetString(PyExc_RuntimeError, _("Job Level can be set only during JobInit"));
284 for (i=0; joblevels[i].level_name; i++) {
285 if (strcmp(strval, joblevels[i].level_name) == 0) {
286 if (joblevels[i].job_type == jcr->JobType) {
287 jcr->JobLevel = joblevels[i].level;
288 jcr->jr.JobLevel = jcr->JobLevel;
293 PyErr_SetString(PyExc_ValueError, _("Bad JobLevel string"));
297 PyErr_SetString(PyExc_AttributeError, attrname);
302 * Set pointer to instantiated events class
304 static PyObject *set_job_events(PyObject *self, PyObject *arg)
309 Dmsg0(100, "In set_job_events.\n");
310 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
311 Dmsg0(000, "Error in ParseTuple\n");
314 jcr = get_jcr_from_PyObject(self);
315 Py_XDECREF((PyObject *)jcr->Python_events);
317 jcr->Python_events = (void *)eObject;
322 /* Run a Bacula job */
323 static PyObject *job_run(PyObject *self, PyObject *arg)
329 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
330 Dmsg0(000, "Error in ParseTuple\n");
333 /* Release lock due to recursion */
334 // PyEval_ReleaseLock();
335 jcr = get_jcr_from_PyObject(self);
336 UAContext *ua = new_ua_context(jcr);
338 pm_strcpy(ua->cmd, item); /* copy command */
339 parse_ua_args(ua); /* parse command */
340 stat = run_cmd(ua, ua->cmd);
342 // PyEval_AcquireLock();
343 return PyInt_FromLong((long)stat);
346 static PyObject *job_write(PyObject *self, PyObject *args)
350 if (!PyArg_ParseTuple(args, "s:write", &text)) {
351 Dmsg0(000, "Parse tuple error in job_write\n");
355 JCR *jcr = get_jcr_from_PyObject(self);
356 Jmsg(jcr, M_INFO, 0, "%s", text);
362 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
364 char *VolName = NULL;
366 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
367 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
373 JCR *jcr = get_jcr_from_PyObject(self);
374 memset(&mr, 0, sizeof(mr));
375 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
376 ok = db_get_media_record(jcr, jcr->db, &mr);
377 return Py_BuildValue("i", ok);
384 static PyObject *job_cancel(PyObject *self, PyObject *args)
390 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
391 Dmsg0(000, "Parse tuple error in job_write\n");
395 if (jcr->JobId == 0) {
398 if (jcr->JobId == JobId) {
403 /* endeach_jcr(jcr) not needed because freed below */
406 /* ***FIXME*** raise exception */
409 // PyEval_ReleaseLock();
410 UAContext *ua = new_ua_context(jcr);
412 if (!cancel_job(ua, jcr)) {
413 /* ***FIXME*** raise exception */
418 // PyEval_AcquireLock();
424 * Generate a Job event, which means look up the event
425 * method defined by the user, and if it exists,
428 int generate_job_event(JCR *jcr, const char *event)
430 PyObject *method = NULL;
431 PyObject *Job = (PyObject *)jcr->Python_job;
432 PyObject *events = (PyObject *)jcr->Python_events;
433 PyObject *result = NULL;
436 if (!Job || !events) {
441 // PyEval_AcquireLock();
443 method = find_method(events, method, event);
448 bstrncpy(jcr->event, event, sizeof(jcr->event));
449 result = PyObject_CallFunction(method, "O", Job);
450 jcr->event[0] = 0; /* no event in progress */
451 if (result == NULL) {
452 if (PyErr_Occurred()) {
454 Dmsg1(000, "Error in Python method %s\n", event);
463 // PyEval_ReleaseLock();
467 bool python_set_prog(JCR*, char const*) { return false; }
471 /* Dummy if Python not configured */
472 int generate_job_event(JCR *jcr, const char *event) { return 1; }
475 #endif /* HAVE_PYTHON */