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->name());
144 case 7: /* Storage */
146 return Py_BuildValue(getvars[i].fmt, jcr->wstore->name());
147 } else if (jcr->rstore) {
148 return Py_BuildValue(getvars[i].fmt, jcr->rstore->name());
153 return Py_BuildValue(getvars[i].fmt, jcr->catalog->name());
154 case 9: /* MediaType */
156 return Py_BuildValue(getvars[i].fmt, jcr->wstore->media_type);
157 } else if (jcr->rstore) {
158 return Py_BuildValue(getvars[i].fmt, jcr->rstore->media_type);
162 case 10: /* JobName */
163 return Py_BuildValue(getvars[i].fmt, jcr->Job);
164 case 11: /* JobStatus */
166 buf[0] = jcr->JobStatus;
167 return Py_BuildValue(getvars[i].fmt, buf);
168 case 12: /* Priority */
169 return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
171 return Py_BuildValue(getvars[i].fmt, jcr->VolumeName);
172 case 14: /* CatalogRes */
173 return Py_BuildValue(getvars[i].fmt,
174 jcr->catalog->db_name, jcr->catalog->db_address,
175 jcr->catalog->db_user, jcr->catalog->db_password,
176 jcr->catalog->db_socket, jcr->catalog->db_port,
180 bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
182 PyErr_SetString(PyExc_AttributeError, errmsg);
187 /* Set Job variables */
191 int job_setattr(PyObject *self, char *attrname, PyObject *value)
199 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
200 if (value == NULL) { /* Cannot delete variables */
203 jcr = get_jcr_from_PyObject(self);
208 /* Find attribute name in list */
209 for (i=0; setvars[i].name; i++) {
210 if (strcmp(setvars[i].name, attrname) == 0) {
218 /* Get argument value */
219 if (setvars[i].fmt != NULL) {
220 switch (setvars[i].fmt[0]) {
222 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
223 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
228 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
229 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
236 case 0: /* JobReport */
237 Jmsg(jcr, M_INFO, 0, "%s", strval);
239 case 1: /* VolumeName */
240 /* Make sure VolumeName is valid and we are in VolumeName event */
241 if (strcmp("NewVolume", jcr->event) == 0 &&
242 is_volume_name_legal(NULL, strval)) {
243 pm_strcpy(jcr->VolumeName, strval);
244 Dmsg1(100, "Set Vol=%s\n", strval);
247 jcr->VolumeName[0] = 0;
250 case 2: /* Priority */
251 Dmsg1(000, "Set priority=%d\n", intval);
252 if (intval >= 1 && intval <= 100) {
253 jcr->JobPriority = intval;
255 PyErr_SetString(PyExc_ValueError, _("Priority must be 1-100"));
258 case 3: /* Job Level */
259 if (strcmp("JobInit", jcr->event) != 0) {
260 PyErr_SetString(PyExc_RuntimeError, _("Job Level can be set only during JobInit"));
263 for (i=0; joblevels[i].level_name; i++) {
264 if (strcmp(strval, joblevels[i].level_name) == 0) {
265 if (joblevels[i].job_type == jcr->JobType) {
266 jcr->JobLevel = joblevels[i].level;
271 PyErr_SetString(PyExc_ValueError, _("Bad JobLevel string"));
275 PyErr_SetString(PyExc_AttributeError, attrname);
280 * Set pointer to instantiated events class
282 static PyObject *set_job_events(PyObject *self, PyObject *arg)
287 Dmsg0(100, "In set_job_events.\n");
288 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
289 Dmsg0(000, "Error in ParseTuple\n");
292 jcr = get_jcr_from_PyObject(self);
293 Py_XDECREF((PyObject *)jcr->Python_events);
295 jcr->Python_events = (void *)eObject;
300 /* Run a Bacula job */
301 static PyObject *job_run(PyObject *self, PyObject *arg)
307 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
308 Dmsg0(000, "Error in ParseTuple\n");
311 /* Release lock due to recursion */
312 // PyEval_ReleaseLock();
313 jcr = get_jcr_from_PyObject(self);
314 UAContext *ua = new_ua_context(jcr);
316 pm_strcpy(ua->cmd, item); /* copy command */
317 parse_ua_args(ua); /* parse command */
318 stat = run_cmd(ua, ua->cmd);
320 // PyEval_AcquireLock();
321 return PyInt_FromLong((long)stat);
324 static PyObject *job_write(PyObject *self, PyObject *args)
328 if (!PyArg_ParseTuple(args, "s:write", &text)) {
329 Dmsg0(000, "Parse tuple error in job_write\n");
333 JCR *jcr = get_jcr_from_PyObject(self);
334 Jmsg(jcr, M_INFO, 0, "%s", text);
340 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
342 char *VolName = NULL;
344 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
345 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
351 JCR *jcr = get_jcr_from_PyObject(self);
352 memset(&mr, 0, sizeof(mr));
353 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
354 ok = db_get_media_record(jcr, jcr->db, &mr);
355 return Py_BuildValue("i", ok);
362 static PyObject *job_cancel(PyObject *self, PyObject *args)
368 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
369 Dmsg0(000, "Parse tuple error in job_write\n");
373 if (jcr->JobId == 0) {
376 if (jcr->JobId == JobId) {
381 /* endeach_jcr(jcr) not needed because freed below */
384 /* ***FIXME*** raise exception */
387 // PyEval_ReleaseLock();
388 UAContext *ua = new_ua_context(jcr);
390 if (!cancel_job(ua, jcr)) {
391 /* ***FIXME*** raise exception */
396 // PyEval_AcquireLock();
402 * Generate a Job event, which means look up the event
403 * method defined by the user, and if it exists,
406 int generate_job_event(JCR *jcr, const char *event)
408 PyObject *method = NULL;
409 PyObject *Job = (PyObject *)jcr->Python_job;
410 PyObject *events = (PyObject *)jcr->Python_events;
411 PyObject *result = NULL;
414 if (!Job || !events) {
419 // PyEval_AcquireLock();
421 method = find_method(events, method, event);
426 bstrncpy(jcr->event, event, sizeof(jcr->event));
427 result = PyObject_CallFunction(method, "O", Job);
428 jcr->event[0] = 0; /* no event in progress */
429 if (result == NULL) {
430 if (PyErr_Occurred()) {
432 Dmsg1(000, "Error in Python method %s\n", event);
441 // PyEval_ReleaseLock();
445 bool python_set_prog(JCR*, char const*) { return false; }
449 /* Dummy if Python not configured */
450 int generate_job_event(JCR *jcr, const char *event) { return 1; }
453 #endif /* HAVE_PYTHON */