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[] = {
62 { N_("DirName"), "s"},
67 { N_("NumVols"), "i"},
69 { N_("Storage"), "s"},
70 { N_("Catalog"), "s"},
71 { N_("MediaType"), "s"},
72 { N_("JobName"), "s"},
73 { N_("JobStatus"), "s"},
74 { N_("Priority"), "i"},
75 { N_("Version"), "(ss)"},
76 { N_("ConfigFile"), "s"},
77 { N_("WorkingDir"), "s"},
78 { N_("CatalogRes"), "(sssssis)"},
83 /* Writable variables */
84 static struct s_vars setvars[] = {
85 { N_("JobReport"), "s"},
86 { N_("VolumeName"), "s"},
87 { N_("Priority"), "i"},
93 /* Return Job variables */
94 /* Returns: NULL if error
95 * PyObject * return value if OK
97 PyObject *job_getattr(PyObject *self, char *attrname)
105 Dmsg0(100, "In job_getattr.\n");
106 jcr = get_jcr_from_PyObject(self);
108 bstrncpy(errmsg, "Job pointer not found.", sizeof(errmsg));
111 for (i=0; getvars[i].name; i++) {
112 if (strcmp(getvars[i].name, attrname) == 0) {
118 /* Try our methods */
119 return Py_FindMethod(JobMethods, self, attrname);
123 return Py_BuildValue(getvars[i].fmt, jcr->job->hdr.name);
124 case 1: /* Director's name */
125 return Py_BuildValue(getvars[i].fmt, my_name);
127 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
129 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
131 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
133 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
134 case 6: /* NumVols */
136 memset(&pr, 0, sizeof(pr));
137 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
138 if (db_get_pool_record(jcr, jcr->db, &pr)) {
139 jcr->NumVols = pr.NumVols;
140 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
142 bsnprintf(errmsg, sizeof(errmsg), "Pool record not found.");
146 return Py_BuildValue(getvars[i].fmt, jcr->pool->hdr.name);
147 case 8: /* Storage */
148 return Py_BuildValue(getvars[i].fmt, jcr->store->hdr.name);
150 return Py_BuildValue(getvars[i].fmt, jcr->catalog->hdr.name);
151 case 10: /* MediaType */
152 return Py_BuildValue(getvars[i].fmt, jcr->store->media_type);
153 case 11: /* JobName */
154 return Py_BuildValue(getvars[i].fmt, jcr->Job);
155 case 12: /* JobStatus */
157 buf[0] = jcr->JobStatus;
158 return Py_BuildValue(getvars[i].fmt, buf);
159 case 13: /* Priority */
160 return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
161 case 14: /* Version */
162 return Py_BuildValue(getvars[i].fmt, VERSION, BDATE);
163 case 15: /* Config Dir */
164 return Py_BuildValue(getvars[i].fmt, configfile);
165 case 16: /* Working Dir */
166 return Py_BuildValue(getvars[i].fmt, director->working_directory);
167 case 17: /* CatalogRes */
168 return Py_BuildValue(getvars[i].fmt,
169 jcr->catalog->db_name, jcr->catalog->db_address,
170 jcr->catalog->db_user, jcr->catalog->db_password,
171 jcr->catalog->db_socket, jcr->catalog->db_port,
175 bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname);
177 PyErr_SetString(PyExc_AttributeError, errmsg);
182 /* Set Job variables */
186 int job_setattr(PyObject *self, char *attrname, PyObject *value)
194 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
195 if (value == NULL) { /* Cannot delete variables */
198 jcr = get_jcr_from_PyObject(self);
203 /* Find attribute name in list */
204 for (i=0; setvars[i].name; i++) {
205 if (strcmp(setvars[i].name, attrname) == 0) {
213 /* Get argument value */
214 if (setvars[i].fmt != NULL) {
215 switch (setvars[i].fmt[0]) {
217 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
218 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
223 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
224 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
231 case 0: /* JobReport */
232 Jmsg(jcr, M_INFO, 0, "%s", strval);
234 case 1: /* VolumeName */
235 /* Make sure VolumeName is valid and we are in VolumeName event */
236 if (strcmp("NewVolume", jcr->event) == 0 &&
237 is_volume_name_legal(NULL, strval)) {
238 pm_strcpy(jcr->VolumeName, strval);
239 Dmsg1(100, "Set Vol=%s\n", strval);
242 jcr->VolumeName[0] = 0;
245 case 2: /* Priority */
246 Dmsg1(000, "Set priority=%d\n", intval);
250 PyErr_SetString(PyExc_AttributeError, attrname);
255 static PyObject *set_job_events(PyObject *self, PyObject *arg)
260 Dmsg0(100, "In set_job_events.\n");
261 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
262 Dmsg0(000, "Error in ParseTuple\n");
265 jcr = get_jcr_from_PyObject(self);
266 Py_XDECREF((PyObject *)jcr->Python_events);
268 jcr->Python_events = (void *)eObject;
273 /* Run a Bacula command */
274 static PyObject *job_run(PyObject *self, PyObject *arg)
280 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
281 Dmsg0(000, "Error in ParseTuple\n");
284 /* Release lock due to recursion */
285 PyEval_ReleaseLock();
286 jcr = get_jcr_from_PyObject(self);
287 UAContext *ua = new_ua_context(jcr);
289 pm_strcpy(ua->cmd, item); /* copy command */
290 parse_ua_args(ua); /* parse command */
291 stat = run_cmd(ua, ua->cmd);
293 PyEval_AcquireLock();
294 return PyInt_FromLong((long)stat);
297 static PyObject *job_write(PyObject *self, PyObject *args)
301 if (!PyArg_ParseTuple(args, "s:write", &text)) {
302 Dmsg0(000, "Parse tuple error in job_write\n");
306 JCR *jcr = get_jcr_from_PyObject(self);
307 Jmsg(jcr, M_INFO, 0, "%s", text);
313 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
315 char *VolName = NULL;
317 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
318 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
324 JCR *jcr = get_jcr_from_PyObject(self);
325 memset(&mr, 0, sizeof(mr));
326 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
327 ok = db_get_media_record(jcr, jcr->db, &mr);
328 return Py_BuildValue("i", ok);
335 static PyObject *job_cancel(PyObject *self, PyObject *args)
341 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
342 Dmsg0(000, "Parse tuple error in job_write\n");
346 if (jcr->JobId == 0) {
350 if (jcr->JobId == JobId) {
356 /* ***FIXME*** raise exception */
359 PyEval_ReleaseLock();
360 UAContext *ua = new_ua_context(jcr);
362 if (!cancel_job(ua, jcr)) {
363 /* ***FIXME*** raise exception */
368 PyEval_AcquireLock();
374 * Generate a Job event, which means look up the event
375 * method defined by the user, and if it exists,
378 int generate_job_event(JCR *jcr, const char *event)
380 PyObject *method = NULL;
381 PyObject *Job = (PyObject *)jcr->Python_job;
382 PyObject *events = (PyObject *)jcr->Python_events;
383 PyObject *result = NULL;
386 if (!Job || !events) {
390 PyEval_AcquireLock();
392 method = find_method(events, method, event);
397 bstrncpy(jcr->event, event, sizeof(jcr->event));
398 result = PyObject_CallFunction(method, "O", Job);
399 jcr->event[0] = 0; /* no event in progress */
400 if (result == NULL) {
401 if (PyErr_Occurred()) {
403 Dmsg1(000, "Error in Python method %s\n", event);
411 PyEval_ReleaseLock();
415 bool python_set_prog(JCR*, char const*) { return false; }
419 /* Dummy if Python not configured */
420 int generate_job_event(JCR *jcr, const char *event) { return 1; }
423 #endif /* HAVE_PYTHON */