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 ammended 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);
43 PyMethodDef JobMethods[] = {
44 {"set_events", set_job_events, METH_VARARGS, "Set Job events"},
45 {"run", job_run, METH_VARARGS, "Run a Job"},
46 {"write", job_write, METH_VARARGS, "Write to output"},
47 {"cancel", job_cancel, METH_VARARGS, "Cancel a Job"},
48 {NULL, NULL, 0, NULL} /* last item */
57 /* Read-only variables */
58 static struct s_vars getvars[] = {
60 { N_("DirName"), "s"},
65 { N_("NumVols"), "i"},
67 { N_("Storage"), "s"},
68 { N_("Catalog"), "s"},
69 { N_("MediaType"), "s"},
70 { N_("JobName"), "s"},
71 { N_("JobStatus"), "s"},
72 { N_("Priority"), "i"},
73 { N_("Version"), "(ss)"},
74 { N_("ConfigFile"), "s"},
75 { N_("WorkingDir"), "s"},
76 { N_("CatalogRes"), "(sssssi)"},
81 /* Writable variables */
82 static struct s_vars setvars[] = {
83 { N_("JobReport"), "s"},
84 { N_("VolumeName"), "s"},
85 { N_("Priority"), "i"},
91 /* Return Job variables */
92 /* Returns: NULL if error
93 * PyObject * return value if OK
95 PyObject *job_getattr(PyObject *self, char *attrname)
103 Dmsg0(100, "In job_getattr.\n");
104 jcr = get_jcr_from_PyObject(self);
106 bstrncpy(errmsg, "Job pointer not found.", sizeof(errmsg));
109 for (i=0; getvars[i].name; i++) {
110 if (strcmp(getvars[i].name, attrname) == 0) {
116 /* Try our methods */
117 return Py_FindMethod(JobMethods, self, attrname);
121 return Py_BuildValue(getvars[i].fmt, jcr->job->hdr.name);
122 case 1: /* Director's name */
123 return Py_BuildValue(getvars[i].fmt, my_name);
125 return Py_BuildValue(getvars[i].fmt, job_level_to_str(jcr->JobLevel));
127 return Py_BuildValue(getvars[i].fmt, job_type_to_str(jcr->JobType));
129 return Py_BuildValue(getvars[i].fmt, jcr->JobId);
131 return Py_BuildValue(getvars[i].fmt, jcr->client->hdr.name);
132 case 6: /* NumVols */
133 return Py_BuildValue(getvars[i].fmt, jcr->NumVols);
135 return Py_BuildValue(getvars[i].fmt, jcr->pool->hdr.name);
136 case 8: /* Storage */
137 return Py_BuildValue(getvars[i].fmt, jcr->store->hdr.name);
139 return Py_BuildValue(getvars[i].fmt, jcr->catalog->hdr.name);
140 case 10: /* MediaType */
141 return Py_BuildValue(getvars[i].fmt, jcr->store->media_type);
142 case 11: /* JobName */
143 return Py_BuildValue(getvars[i].fmt, jcr->Job);
144 case 12: /* JobStatus */
146 buf[0] = jcr->JobStatus;
147 return Py_BuildValue(getvars[i].fmt, buf);
148 case 13: /* Priority */
149 return Py_BuildValue(getvars[i].fmt, jcr->JobPriority);
150 case 14: /* Version */
151 return Py_BuildValue(getvars[i].fmt, VERSION, BDATE);
152 case 15: /* Config Dir */
153 return Py_BuildValue(getvars[i].fmt, configfile);
154 case 16: /* Working Dir */
155 return Py_BuildValue(getvars[i].fmt, director->working_directory);
156 case 17: /* CatalogRes */
157 return Py_BuildValue(getvars[i].fmt,
158 jcr->catalog->db_name, jcr->catalog->db_address,
159 jcr->catalog->db_user, jcr->catalog->db_password,
160 jcr->catalog->db_socket, jcr->catalog->db_port);
163 bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname);
165 PyErr_SetString(PyExc_AttributeError, errmsg);
170 /* Set Job variables */
174 int job_setattr(PyObject *self, char *attrname, PyObject *value)
182 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
183 if (value == NULL) { /* Cannot delete variables */
186 jcr = get_jcr_from_PyObject(self);
191 /* Find attribute name in list */
192 for (i=0; setvars[i].name; i++) {
193 if (strcmp(setvars[i].name, attrname) == 0) {
201 /* Get argument value */
202 if (setvars[i].fmt != NULL) {
203 switch (setvars[i].fmt[0]) {
205 if (!PyArg_Parse(value, setvars[i].fmt, &strval)) {
206 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
211 if (!PyArg_Parse(value, setvars[i].fmt, &intval)) {
212 PyErr_SetString(PyExc_TypeError, "Read-only attribute");
219 case 0: /* JobReport */
220 Jmsg(jcr, M_INFO, 0, "%s", strval);
222 case 1: /* VolumeName */
223 /* Make sure VolumeName is valid and we are in VolumeName event */
224 if (strcmp("NewVolume", jcr->event) == 0 &&
225 is_volume_name_legal(NULL, strval)) {
226 pm_strcpy(jcr->VolumeName, strval);
227 Dmsg1(100, "Set Vol=%s\n", strval);
230 jcr->VolumeName[0] = 0;
233 case 2: /* Priority */
234 Dmsg1(000, "Set priority=%d\n", intval);
238 PyErr_SetString(PyExc_AttributeError, attrname);
243 static PyObject *set_job_events(PyObject *self, PyObject *arg)
248 Dmsg0(100, "In set_job_events.\n");
249 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
250 Dmsg0(000, "Error in ParseTuple\n");
253 jcr = get_jcr_from_PyObject(self);
254 Py_XDECREF((PyObject *)jcr->Python_events);
256 jcr->Python_events = (void *)eObject;
261 /* Run a Bacula command */
262 static PyObject *job_run(PyObject *self, PyObject *arg)
268 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
269 Dmsg0(000, "Error in ParseTuple\n");
272 /* Release lock due to recursion */
273 PyEval_ReleaseLock();
274 jcr = get_jcr_from_PyObject(self);
275 UAContext *ua = new_ua_context(jcr);
277 pm_strcpy(ua->cmd, item); /* copy command */
278 parse_ua_args(ua); /* parse command */
279 stat = run_cmd(ua, ua->cmd);
281 PyEval_AcquireLock();
282 return PyInt_FromLong((long)stat);
285 static PyObject *job_write(PyObject *self, PyObject *args)
289 if (!PyArg_ParseTuple(args, "s:write", &text)) {
290 Dmsg0(000, "Parse tuple error in job_write\n");
294 Jmsg(NULL, M_INFO, 0, "%s", text);
300 static PyObject *job_cancel(PyObject *self, PyObject *args)
306 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
307 Dmsg0(000, "Parse tuple error in job_write\n");
311 if (jcr->JobId == 0) {
315 if (jcr->JobId == JobId) {
321 /* ***FIXME*** raise exception */
324 PyEval_ReleaseLock();
325 UAContext *ua = new_ua_context(jcr);
327 if (!cancel_job(ua, jcr)) {
328 /* ***FIXME*** raise exception */
333 PyEval_AcquireLock();
339 * Generate a Job event, which means look up the event
340 * method defined by the user, and if it exists,
343 int generate_job_event(JCR *jcr, const char *event)
345 PyObject *method = NULL;
346 PyObject *Job = (PyObject *)jcr->Python_job;
347 PyObject *events = (PyObject *)jcr->Python_events;
348 PyObject *result = NULL;
351 if (!Job || !events) {
355 PyEval_AcquireLock();
357 method = find_method(events, method, event);
362 bstrncpy(jcr->event, event, sizeof(jcr->event));
363 result = PyObject_CallFunction(method, "O", Job);
364 jcr->event[0] = 0; /* no event in progress */
365 if (result == NULL) {
366 if (PyErr_Occurred()) {
368 Dmsg1(000, "Error in Python method %s\n", event);
376 PyEval_ReleaseLock();
380 bool python_set_prog(JCR*, char const*) { return false; }
384 /* Dummy if Python not configured */
385 int generate_job_event(JCR *jcr, const char *event) { return 1; }
388 #endif /* HAVE_PYTHON */