3 * Bacula interface to Python for the Director
5 * Kern Sibbald, November MMIV
11 Copyright (C) 2004-2005 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 static PyObject *set_job_events(PyObject *self, PyObject *arg)
251 Dmsg0(100, "In set_job_events.\n");
252 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
253 Dmsg0(000, "Error in ParseTuple\n");
256 jcr = get_jcr_from_PyObject(self);
257 Py_XDECREF((PyObject *)jcr->Python_events);
259 jcr->Python_events = (void *)eObject;
264 /* Run a Bacula command */
265 static PyObject *job_run(PyObject *self, PyObject *arg)
271 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
272 Dmsg0(000, "Error in ParseTuple\n");
275 /* Release lock due to recursion */
276 PyEval_ReleaseLock();
277 jcr = get_jcr_from_PyObject(self);
278 UAContext *ua = new_ua_context(jcr);
280 pm_strcpy(ua->cmd, item); /* copy command */
281 parse_ua_args(ua); /* parse command */
282 stat = run_cmd(ua, ua->cmd);
284 PyEval_AcquireLock();
285 return PyInt_FromLong((long)stat);
288 static PyObject *job_write(PyObject *self, PyObject *args)
292 if (!PyArg_ParseTuple(args, "s:write", &text)) {
293 Dmsg0(000, "Parse tuple error in job_write\n");
297 JCR *jcr = get_jcr_from_PyObject(self);
298 Jmsg(jcr, M_INFO, 0, "%s", text);
304 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
306 char *VolName = NULL;
308 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
309 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
315 JCR *jcr = get_jcr_from_PyObject(self);
316 memset(&mr, 0, sizeof(mr));
317 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
318 ok = db_get_media_record(jcr, jcr->db, &mr);
319 return Py_BuildValue("i", ok);
326 static PyObject *job_cancel(PyObject *self, PyObject *args)
332 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
333 Dmsg0(000, "Parse tuple error in job_write\n");
337 if (jcr->JobId == 0) {
341 if (jcr->JobId == JobId) {
347 /* ***FIXME*** raise exception */
350 PyEval_ReleaseLock();
351 UAContext *ua = new_ua_context(jcr);
353 if (!cancel_job(ua, jcr)) {
354 /* ***FIXME*** raise exception */
359 PyEval_AcquireLock();
365 * Generate a Job event, which means look up the event
366 * method defined by the user, and if it exists,
369 int generate_job_event(JCR *jcr, const char *event)
371 PyObject *method = NULL;
372 PyObject *Job = (PyObject *)jcr->Python_job;
373 PyObject *events = (PyObject *)jcr->Python_events;
374 PyObject *result = NULL;
377 if (!Job || !events) {
381 PyEval_AcquireLock();
383 method = find_method(events, method, event);
388 bstrncpy(jcr->event, event, sizeof(jcr->event));
389 result = PyObject_CallFunction(method, "O", Job);
390 jcr->event[0] = 0; /* no event in progress */
391 if (result == NULL) {
392 if (PyErr_Occurred()) {
394 Dmsg1(000, "Error in Python method %s\n", event);
402 PyEval_ReleaseLock();
406 bool python_set_prog(JCR*, char const*) { return false; }
410 /* Dummy if Python not configured */
411 int generate_job_event(JCR *jcr, const char *event) { return 1; }
414 #endif /* HAVE_PYTHON */