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)"},
81 /* Writable variables */
82 static struct s_vars setvars[] = {
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);
124 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
126 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
128 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
130 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
131 case 5: /* NumVols */
133 memset(&pr, 0, sizeof(pr));
134 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
135 if (db_get_pool_record(jcr, jcr->db, &pr)) {
136 jcr->NumVols = pr.NumVols;
137 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
139 bsnprintf(errmsg, sizeof(errmsg), _("Pool record not found."));
143 return Py_BuildValue(getvars[i].fmt, jcr->pool->hdr.name);
144 case 7: /* Storage */
145 return Py_BuildValue(getvars[i].fmt, jcr->store->hdr.name);
147 return Py_BuildValue(getvars[i].fmt, jcr->catalog->hdr.name);
148 case 9: /* MediaType */
149 return Py_BuildValue(getvars[i].fmt, jcr->store->media_type);
150 case 10: /* JobName */
151 return Py_BuildValue(getvars[i].fmt, jcr->Job);
152 case 11: /* JobStatus */
154 buf[0] = jcr->JobStatus;
155 return Py_BuildValue(getvars[i].fmt, buf);
156 case 12: /* Priority */
157 return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
159 return Py_BuildValue(getvars[i].fmt, jcr->VolumeName);
160 case 14: /* CatalogRes */
161 return Py_BuildValue(getvars[i].fmt,
162 jcr->catalog->db_name, jcr->catalog->db_address,
163 jcr->catalog->db_user, jcr->catalog->db_password,
164 jcr->catalog->db_socket, jcr->catalog->db_port,
168 bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
170 PyErr_SetString(PyExc_AttributeError, errmsg);
175 /* Set Job variables */
179 int job_setattr(PyObject *self, char *attrname, PyObject *value)
187 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
188 if (value == NULL) { /* Cannot delete variables */
191 jcr = get_jcr_from_PyObject(self);
196 /* Find attribute name in list */
197 for (i=0; setvars[i].name; i++) {
198 if (strcmp(setvars[i].name, attrname) == 0) {
206 /* Get argument value */
207 if (setvars[i].fmt != NULL) {
208 switch (setvars[i].fmt[0]) {
210 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
211 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
216 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
217 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
224 case 0: /* JobReport */
225 Jmsg(jcr, M_INFO, 0, "%s", strval);
227 case 1: /* VolumeName */
228 /* Make sure VolumeName is valid and we are in VolumeName event */
229 if (strcmp("NewVolume", jcr->event) == 0 &&
230 is_volume_name_legal(NULL, strval)) {
231 pm_strcpy(jcr->VolumeName, strval);
232 Dmsg1(100, "Set Vol=%s\n", strval);
235 jcr->VolumeName[0] = 0;
238 case 2: /* Priority */
239 Dmsg1(000, "Set priority=%d\n", intval);
240 if (intval >= 1 && intval <= 100) {
241 jcr->JobPriority = intval;
243 PyErr_SetString(PyExc_ValueError, _("Priority must be 1-100"));
246 case 3: /* Job Level */
247 if (strcmp("JobInit", jcr->event) != 0) {
248 PyErr_SetString(PyExc_RuntimeError, _("Job Level can be set only during JobInit"));
251 for (i=0; joblevels[i].level_name; i++) {
252 if (strcmp(strval, joblevels[i].level_name) == 0) {
253 if (joblevels[i].job_type == jcr->JobType) {
254 jcr->JobLevel = joblevels[i].level;
259 PyErr_SetString(PyExc_ValueError, _("Bad JobLevel string"));
263 PyErr_SetString(PyExc_AttributeError, attrname);
268 * Set pointer to instantiated events class
270 static PyObject *set_job_events(PyObject *self, PyObject *arg)
275 Dmsg0(100, "In set_job_events.\n");
276 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
277 Dmsg0(000, "Error in ParseTuple\n");
280 jcr = get_jcr_from_PyObject(self);
281 Py_XDECREF((PyObject *)jcr->Python_events);
283 jcr->Python_events = (void *)eObject;
288 /* Run a Bacula job */
289 static PyObject *job_run(PyObject *self, PyObject *arg)
295 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
296 Dmsg0(000, "Error in ParseTuple\n");
299 /* Release lock due to recursion */
300 PyEval_ReleaseLock();
301 jcr = get_jcr_from_PyObject(self);
302 UAContext *ua = new_ua_context(jcr);
304 pm_strcpy(ua->cmd, item); /* copy command */
305 parse_ua_args(ua); /* parse command */
306 stat = run_cmd(ua, ua->cmd);
308 PyEval_AcquireLock();
309 return PyInt_FromLong((long)stat);
312 static PyObject *job_write(PyObject *self, PyObject *args)
316 if (!PyArg_ParseTuple(args, "s:write", &text)) {
317 Dmsg0(000, "Parse tuple error in job_write\n");
321 JCR *jcr = get_jcr_from_PyObject(self);
322 Jmsg(jcr, M_INFO, 0, "%s", text);
328 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
330 char *VolName = NULL;
332 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
333 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
339 JCR *jcr = get_jcr_from_PyObject(self);
340 memset(&mr, 0, sizeof(mr));
341 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
342 ok = db_get_media_record(jcr, jcr->db, &mr);
343 return Py_BuildValue("i", ok);
350 static PyObject *job_cancel(PyObject *self, PyObject *args)
356 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
357 Dmsg0(000, "Parse tuple error in job_write\n");
361 if (jcr->JobId == 0) {
364 if (jcr->JobId == JobId) {
369 /* endeach_jcr(jcr) not needed because freed below */
372 /* ***FIXME*** raise exception */
375 PyEval_ReleaseLock();
376 UAContext *ua = new_ua_context(jcr);
378 if (!cancel_job(ua, jcr)) {
379 /* ***FIXME*** raise exception */
384 PyEval_AcquireLock();
390 * Generate a Job event, which means look up the event
391 * method defined by the user, and if it exists,
394 int generate_job_event(JCR *jcr, const char *event)
396 PyObject *method = NULL;
397 PyObject *Job = (PyObject *)jcr->Python_job;
398 PyObject *events = (PyObject *)jcr->Python_events;
399 PyObject *result = NULL;
402 if (!Job || !events) {
406 PyEval_AcquireLock();
408 method = find_method(events, method, event);
413 bstrncpy(jcr->event, event, sizeof(jcr->event));
414 result = PyObject_CallFunction(method, "O", Job);
415 jcr->event[0] = 0; /* no event in progress */
416 if (result == NULL) {
417 if (PyErr_Occurred()) {
419 Dmsg1(000, "Error in Python method %s\n", event);
427 PyEval_ReleaseLock();
431 bool python_set_prog(JCR*, char const*) { return false; }
435 /* Dummy if Python not configured */
436 int generate_job_event(JCR *jcr, const char *event) { return 1; }
439 #endif /* HAVE_PYTHON */