2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula interface to Python for the Director
32 * Kern Sibbald, November MMIV
42 #undef _POSIX_C_SOURCE
45 #include <lib/pythonlib.h>
47 extern struct s_jl joblevels[];
49 static PyObject *set_job_events(PyObject *self, PyObject *arg);
50 static PyObject *job_run(PyObject *self, PyObject *arg);
51 static PyObject *job_write(PyObject *self, PyObject *arg);
52 static PyObject *job_cancel(PyObject *self, PyObject *arg);
53 static PyObject *job_does_vol_exist(PyObject *self, PyObject *arg);
55 PyMethodDef JobMethods[] = {
56 {"set_events", set_job_events, METH_VARARGS, "Set Job events"},
57 {"run", job_run, METH_VARARGS, "Run a Job"},
58 {"write", job_write, METH_VARARGS, "Write to output"},
59 {"cancel", job_cancel, METH_VARARGS, "Cancel a Job"},
60 {"DoesVolumeExist", job_does_vol_exist, METH_VARARGS, "Does Volume Exist"},
61 {NULL, NULL, 0, NULL} /* last item */
69 /* Read-only variables */
70 static struct s_vars getvars[] = {
85 { "CatalogRes", "(sssssis)"},
96 /* Writable variables */
97 static struct s_vars setvars[] = {
107 /* Return Job variables */
108 /* Returns: NULL if error
109 * PyObject * return value if OK
111 PyObject *job_getattr(PyObject *self, char *attrname)
119 Dmsg0(100, "In job_getattr.\n");
120 jcr = get_jcr_from_PyObject(self);
122 bstrncpy(errmsg, _("Job pointer not found."), sizeof(errmsg));
125 for (i=0; getvars[i].name; i++) {
126 if (strcmp(getvars[i].name, attrname) == 0) {
132 /* Try our methods */
133 return Py_FindMethod(JobMethods, self, attrname);
137 return Py_BuildValue((char *)getvars[i].fmt, jcr->job->hdr.name);
139 return Py_BuildValue((char *)getvars[i].fmt, job_level_to_str(jcr->getJobLevel()));
141 return Py_BuildValue((char *)getvars[i].fmt, job_type_to_str(jcr->getJobType()));
143 return Py_BuildValue((char *)getvars[i].fmt, jcr->JobId);
145 return Py_BuildValue((char *)getvars[i].fmt, jcr->client->hdr.name);
146 case 5: /* NumVols */
148 memset(&pr, 0, sizeof(pr));
149 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
150 if (db_get_pool_record(jcr, jcr->db, &pr)) {
151 jcr->NumVols = pr.NumVols;
152 return Py_BuildValue((char *)getvars[i].fmt, jcr->NumVols);
154 bsnprintf(errmsg, sizeof(errmsg), _("Pool record not found."));
158 return Py_BuildValue((char *)getvars[i].fmt, jcr->pool->name());
159 case 7: /* Storage */
161 return Py_BuildValue((char *)getvars[i].fmt, jcr->wstore->name());
162 } else if (jcr->rstore) {
163 return Py_BuildValue((char *)getvars[i].fmt, jcr->rstore->name());
168 return Py_BuildValue((char *)getvars[i].fmt, jcr->catalog->name());
169 case 9: /* MediaType */
171 return Py_BuildValue((char *)getvars[i].fmt, jcr->wstore->media_type);
172 } else if (jcr->rstore) {
173 return Py_BuildValue((char *)getvars[i].fmt, jcr->rstore->media_type);
177 case 10: /* JobName */
178 return Py_BuildValue((char *)getvars[i].fmt, jcr->Job);
179 case 11: /* JobStatus */
181 buf[0] = jcr->JobStatus;
182 return Py_BuildValue((char *)getvars[i].fmt, buf);
183 case 12: /* Priority */
184 return Py_BuildValue((char *)getvars[i].fmt, jcr->JobPriority);
186 return Py_BuildValue((char *)getvars[i].fmt, jcr->VolumeName);
187 case 14: /* CatalogRes */
188 return Py_BuildValue((char *)getvars[i].fmt,
189 jcr->catalog->db_name, jcr->catalog->db_address,
190 jcr->catalog->db_user, jcr->catalog->db_password,
191 jcr->catalog->db_socket, jcr->catalog->db_port,
193 case 15: /* JobErrors */
194 return Py_BuildValue((char *)getvars[i].fmt, jcr->JobErrors);
195 case 16: /* JobFiles */
196 return Py_BuildValue((char *)getvars[i].fmt, jcr->JobFiles);
197 case 17: /* SDJobFiles */
198 return Py_BuildValue((char *)getvars[i].fmt, jcr->SDJobFiles);
199 case 18: /* SDErrors */
200 return Py_BuildValue((char *)getvars[i].fmt, jcr->SDErrors);
201 case 19: /* FDJobStatus */
203 buf[0] = jcr->FDJobStatus;
204 return Py_BuildValue((char *)getvars[i].fmt, buf);
205 case 29: /* SDJobStatus */
207 buf[0] = jcr->SDJobStatus;
208 return Py_BuildValue((char *)getvars[i].fmt, buf);
210 bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
212 PyErr_SetString(PyExc_AttributeError, errmsg);
217 /* Set Job variables */
221 int job_setattr(PyObject *self, char *attrname, PyObject *value)
229 Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value);
230 if (value == NULL) { /* Cannot delete variables */
233 jcr = get_jcr_from_PyObject(self);
238 /* Find attribute name in list */
239 for (i=0; setvars[i].name; i++) {
240 if (strcmp(setvars[i].name, attrname) == 0) {
248 /* Get argument value */
249 if (setvars[i].fmt != NULL) {
250 switch (setvars[i].fmt[0]) {
252 if (!PyArg_Parse(value, (char *)setvars[i].fmt, &strval)) {
253 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
258 if (!PyArg_Parse(value, (char *)setvars[i].fmt, &intval)) {
259 PyErr_SetString(PyExc_TypeError, _("Read-only attribute"));
266 case 0: /* JobReport */
267 Jmsg(jcr, M_INFO, 0, "%s", strval);
269 case 1: /* VolumeName */
270 /* Make sure VolumeName is valid and we are in VolumeName event */
271 if (strcmp("NewVolume", jcr->event) == 0 &&
272 is_volume_name_legal(NULL, strval)) {
273 pm_strcpy(jcr->VolumeName, strval);
274 Dmsg1(100, "Set Vol=%s\n", strval);
277 jcr->VolumeName[0] = 0;
280 case 2: /* Priority */
281 Dmsg1(000, "Set priority=%d\n", intval);
282 if (intval >= 1 && intval <= 100) {
283 jcr->JobPriority = intval;
285 PyErr_SetString(PyExc_ValueError, _("Priority must be 1-100"));
288 case 3: /* Job Level */
289 if (strcmp("JobInit", jcr->event) != 0) {
290 PyErr_SetString(PyExc_RuntimeError, _("Job Level can be set only during JobInit"));
293 if (strval != NULL) {
294 for (i=0; joblevels[i].level_name; i++) {
295 if (strcmp(strval, joblevels[i].level_name) == 0) {
296 if (joblevels[i].job_type == jcr->getJobType()) {
297 jcr->set_JobLevel(joblevels[i].level);
298 jcr->jr.JobLevel = jcr->getJobLevel();
304 PyErr_SetString(PyExc_ValueError, _("Bad JobLevel string"));
308 PyErr_SetString(PyExc_AttributeError, attrname);
313 * Set pointer to instantiated events class
315 static PyObject *set_job_events(PyObject *self, PyObject *arg)
320 Dmsg0(100, "In set_job_events.\n");
321 if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) {
322 Dmsg0(000, "Error in ParseTuple\n");
325 jcr = get_jcr_from_PyObject(self);
326 Py_XDECREF((PyObject *)jcr->Python_events);
328 jcr->Python_events = (void *)eObject;
333 /* Run a Bacula job */
334 static PyObject *job_run(PyObject *self, PyObject *arg)
340 if (!PyArg_ParseTuple(arg, "s:run", &item)) {
341 Dmsg0(000, "Error in ParseTuple\n");
344 /* Release lock due to recursion */
345 // PyEval_ReleaseLock();
346 jcr = get_jcr_from_PyObject(self);
347 UAContext *ua = new_ua_context(jcr);
349 pm_strcpy(ua->cmd, item); /* copy command */
350 parse_ua_args(ua); /* parse command */
351 stat = run_cmd(ua, ua->cmd);
353 // PyEval_AcquireLock();
354 return PyInt_FromLong((long)stat);
357 static PyObject *job_write(PyObject *self, PyObject *args)
361 if (!PyArg_ParseTuple(args, "s:write", &text)) {
362 Dmsg0(000, "Parse tuple error in job_write\n");
366 JCR *jcr = get_jcr_from_PyObject(self);
367 Jmsg(jcr, M_INFO, 0, "%s", text);
373 static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
375 char *VolName = NULL;
377 if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
378 Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
384 JCR *jcr = get_jcr_from_PyObject(self);
385 memset(&mr, 0, sizeof(mr));
386 bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
387 ok = db_get_media_record(jcr, jcr->db, &mr);
388 return Py_BuildValue("i", ok);
395 static PyObject *job_cancel(PyObject *self, PyObject *args)
401 if (!PyArg_ParseTuple(args, "i:cancel", &JobId)) {
402 Dmsg0(000, "Parse tuple error in job_write\n");
406 if (jcr->JobId == 0) {
409 if (jcr->JobId == JobId) {
414 /* endeach_jcr(jcr) not needed because freed below */
417 /* ***FIXME*** raise exception */
420 // PyEval_ReleaseLock();
421 UAContext *ua = new_ua_context(jcr);
423 if (!cancel_job(ua, jcr)) {
424 /* ***FIXME*** raise exception */
429 // PyEval_AcquireLock();
435 * Generate a Job event, which means look up the event
436 * method defined by the user, and if it exists,
439 int generate_job_event(JCR *jcr, const char *event)
441 PyObject *method = NULL;
442 PyObject *Job = (PyObject *)jcr->Python_job;
443 PyObject *events = (PyObject *)jcr->Python_events;
444 PyObject *result = NULL;
447 if (!Job || !events) {
452 // PyEval_AcquireLock();
454 method = find_method(events, method, event);
459 bstrncpy(jcr->event, event, sizeof(jcr->event));
460 result = PyObject_CallFunction(method, (char *)"O", Job);
461 jcr->event[0] = 0; /* no event in progress */
462 if (result == NULL) {
463 if (PyErr_Occurred()) {
465 Dmsg1(000, "Error in Python method %s\n", event);
474 // PyEval_ReleaseLock();
478 bool python_set_prog(JCR*, char const*) { return false; }
482 /* Dummy if Python not configured */
483 int generate_job_event(JCR *jcr, const char *event) { return 1; }
486 #endif /* HAVE_PYTHON */