3 * Bacula common code library interface to Python
5 * Kern Sibbald, November MMIV
12 Copyright (C) 2004-2005 Kern Sibbald
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of
17 the License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public
25 License along with this program; if not, write to the Free
26 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
36 #undef _POSIX_C_SOURCE
39 static PyObject *bacula_module = NULL; /* We create this */
40 static PyObject *StartUp_module = NULL; /* We import this */
42 /* These are the daemon events or methods that are defined */
43 static PyObject *JobStart_method = NULL;
44 static PyObject *JobEnd_method = NULL;
45 static PyObject *Exit_method = NULL;
48 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
49 static PyObject *bacula_write(PyObject *self, PyObject *args);
51 PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name);
53 /* Define Bacula daemon method entry points */
54 static PyMethodDef BaculaMethods[] = {
55 {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
56 {"write", bacula_write, METH_VARARGS, "Write output."},
57 {NULL, NULL, 0, NULL} /* last item */
62 * This is a Bacula Job type as defined in Python. We store a pointer
63 * to the jcr. That is all we need, but the user's script may keep
64 * local data attached to this.
66 typedef struct JCRObject {
71 static PyTypeObject JCRType = {
72 PyObject_HEAD_INIT(NULL)
74 "bacula.jcr", /*tp_name*/
75 sizeof(JCRObject), /*tp_basicsize*/
92 Py_TPFLAGS_DEFAULT, /*tp_flags*/
93 "JCR objects", /* tp_doc */
96 0, /* tp_richcompare */
97 0, /* tp_weaklistoffset */
105 0, /* tp_descr_get */
106 0, /* tp_descr_set */
107 0, /* tp_dictoffset */
113 /* Return the JCR pointer from the JCRObject */
114 JCR *get_jcr_from_PyObject(PyObject *self)
116 return ((JCRObject *)self)->jcr;
120 /* Start the interpreter */
121 void init_python_interpreter(const char *progname, const char *scripts,
125 Py_SetProgramName((char *)progname);
127 PyEval_InitThreads();
128 bacula_module = Py_InitModule("bacula", BaculaMethods);
129 if (!bacula_module) {
130 Jmsg(NULL, M_ERROR_TERM, 0, "Could not initialize Python\n");
132 bsnprintf(buf, sizeof(buf), "import sys\n"
133 "sys.path.append('%s')\n", scripts);
134 if (PyRun_SimpleString(buf) != 0) {
135 Jmsg(NULL, M_ERROR_TERM, 0, "Could not Run Python string %s\n", buf);
137 JCRType.tp_methods = BaculaMethods;
138 if(PyType_Ready(&JCRType) != 0) {
139 Jmsg(NULL, M_ERROR_TERM, 0, "Could not initialize Python Job type.\n");
142 StartUp_module = PyImport_ImportModule((char *)module);
143 if (!StartUp_module) {
144 Jmsg(NULL, M_ERROR_TERM, 0, "Could not import script %s/%s.\n",
148 PyEval_ReleaseLock();
152 void term_python_interpreter()
154 Py_XDECREF(StartUp_module);
158 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
161 if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
164 JobStart_method = find_method(eObject, JobStart_method, "JobStart");
165 JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
166 Exit_method = find_method(eObject, Exit_method, "Exit");
173 /* Write text to daemon output */
174 static PyObject *bacula_write(PyObject *self, PyObject *args)
177 if (!PyArg_ParseTuple(args, "s:write", &text)) {
181 Jmsg(NULL, M_INFO, 0, "%s", text);
189 * Check that a method exists and is callable.
191 PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name)
193 Py_XDECREF(method); /* release old method if any */
194 method = PyObject_GetAttrString(eventsObject, name);
195 if (method == NULL) {
196 Dmsg1(000, "Python method %s not found\n", name);
197 } else if (PyCallable_Check(method) == 0) {
198 Dmsg1(000, "Python object %s found but not a method.\n", name);
202 Dmsg1(000, "Got method %s\n", name);
209 * Generate and process a Bacula event by importing a Python
210 * module and running it.
212 * Returns: 0 if Python not configured or module not found
216 int generate_daemon_event(JCR *jcr, const char *event)
220 PyObject *result = NULL;
222 PyEval_AcquireLock();
223 if (strcmp(event, "JobStart") == 0) {
224 if (!JobStart_method) {
228 /* Create JCR argument to send to function */
229 pJCR = (PyObject *)PyObject_New(JCRObject, &JCRType);
231 Jmsg(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
234 ((JCRObject *)pJCR)->jcr = jcr;
235 bstrncpy(jcr->event, event, sizeof(jcr->event));
236 result = PyObject_CallFunction(JobStart_method, "O", pJCR);
237 jcr->event[0] = 0; /* no event in progress */
238 if (result == NULL) {
239 JobStart_method = NULL;
240 if (PyErr_Occurred()) {
243 Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
247 jcr->Python_jcr = (void *)pJCR;
250 } else if (strcmp(event, "JobEnd") == 0) {
251 if (!JobEnd_method) {
252 Py_XDECREF((PyObject *)jcr->Python_jcr);
256 bstrncpy(jcr->event, event, sizeof(jcr->event));
257 result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_jcr);
258 jcr->event[0] = 0; /* no event in progress */
259 if (result == NULL) {
260 JobEnd_method = NULL;
261 if (PyErr_Occurred()) {
264 Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
265 Py_XDECREF((PyObject *)jcr->Python_jcr);
268 Py_XDECREF((PyObject *)jcr->Python_jcr);
274 PyEval_ReleaseLock();
279 PyObject *pName, *pModule, *pDict, *pFunc;
280 PyObject *pArgs, *pJCR, *pCall;
282 Dmsg1(100, "Generate event %s\n", event);
283 pName = PyString_FromString(event);
285 Jmsg(jcr, M_ERROR, 0, "Could not convert \"%s\" to Python string.\n", event);
286 return -1; /* Could not convert string */
289 pModule = PyImport_Import(pName);
290 Py_DECREF(pName); /* release pName */
292 if (pModule != NULL) {
293 pDict = PyModule_GetDict(pModule);
294 /* pDict is a borrowed reference */
296 pFunc = PyDict_GetItemString(pDict, (char *)event);
297 /* pFun: Borrowed reference */
299 if (pFunc && PyCallable_Check(pFunc)) {
300 /* Create JCR argument to send to function */
301 pArgs = PyTuple_New(1);
302 pJCR = (PyObject *)PyObject_New(JCRObject, &JCRType);
303 ((JCRObject *)pJCR)->jcr = jcr;
307 Jmsg(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
311 /* pJCR reference stolen here: */
312 PyTuple_SetItem(pArgs, 0, pJCR);
314 /* Finally, we call the module here */
315 bstrncpy(jcr->event, event, sizeof(jcr->event));
316 pCall = PyObject_CallObject(pFunc, pArgs);
317 jcr->event[0] = 0; /* no event in progress */
325 Jmsg(jcr, M_ERROR, 0, "Error running Python module: %s\n", event);
326 return 0; /* error running function */
328 /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
330 if (PyErr_Occurred()) {
333 Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found in module.\n", event);
334 return -1; /* function not found */
338 return 0; /* Module not present */
340 Dmsg0(100, "Generate event OK\n");
348 * No Python configured -- create external entry points and
349 * dummy routines so that library code can call this without
350 * problems even if it is not configured.
352 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
353 void init_python_interpreter(const char *progname, const char *scripts,
354 const char *module) { }
355 void term_python_interpreter() { }
357 #endif /* HAVE_PYTHON */