3 * Bacula common code library interface to Python
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.
30 #undef _POSIX_C_SOURCE
33 /* Imported subroutines */
34 //extern PyMethodDef JobMethods[];
35 extern PyObject *job_getattr(PyObject *self, char *attrname);
36 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
38 static PyObject *bacula_module = NULL; /* We create this */
39 static PyObject *StartUp_module = NULL; /* We import this */
41 /* These are the daemon events or methods that are defined */
42 static PyObject *JobStart_method = NULL;
43 static PyObject *JobEnd_method = NULL;
44 static PyObject *Exit_method = NULL;
46 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
47 static PyObject *bacula_write(PyObject *self, PyObject *args);
49 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
51 /* Define Bacula daemon method entry points */
52 static PyMethodDef BaculaMethods[] = {
53 {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
54 {"write", bacula_write, METH_VARARGS, "Write output."},
55 {NULL, NULL, 0, NULL} /* last item */
60 * This is a Bacula Job type as defined in Python. We store a pointer
61 * to the jcr. That is all we need, but the user's script may keep
62 * local data attached to this.
64 typedef struct s_JobObject {
69 static PyTypeObject JobType = {
70 PyObject_HEAD_INIT(NULL)
71 /* Other items filled in in code below */
74 /* Return the JCR pointer from the JobObject */
75 JCR *get_jcr_from_PyObject(PyObject *self)
80 return ((JobObject *)self)->jcr;
84 /* Start the interpreter */
85 void init_python_interpreter(const char *progname, const char *scripts,
90 if (!scripts || scripts[0] == 0) {
91 Dmsg1(100, "No script dir. prog=%s\n", module);
94 Dmsg2(100, "Script dir=%s prog=%s\n", scripts, module);
96 Py_SetProgramName((char *)progname);
99 bacula_module = Py_InitModule("bacula", BaculaMethods);
100 PyModule_AddStringConstant(bacula_module, "name", my_name);
101 if (!bacula_module) {
102 Jmsg0(NULL, M_ERROR_TERM, 0, "Could not initialize Python\n");
104 bsnprintf(buf, sizeof(buf), "import sys\n"
105 "sys.path.append('%s')\n", scripts);
106 if (PyRun_SimpleString(buf) != 0) {
107 Jmsg1(NULL, M_ERROR_TERM, 0, "Could not Run Python string %s\n", buf);
110 /* Explicitly set values we want */
111 JobType.tp_name = "Bacula.Job";
112 JobType.tp_basicsize = sizeof(JobObject);
113 JobType.tp_flags = Py_TPFLAGS_DEFAULT;
114 JobType.tp_doc = "Bacula Job object";
115 JobType.tp_getattr = job_getattr;
116 JobType.tp_setattr = job_setattr;
118 if (PyType_Ready(&JobType) != 0) {
119 Jmsg0(NULL, M_ERROR_TERM, 0, "Could not initialize Python Job type.\n");
122 StartUp_module = PyImport_ImportModule((char *)module);
123 if (!StartUp_module) {
124 Emsg2(M_ERROR, 0, "Could not import Python script %s/%s. Python disabled.\n",
126 if (PyErr_Occurred()) {
128 Dmsg0(000, "Python Import error.\n");
131 PyEval_ReleaseLock();
135 void term_python_interpreter()
137 if (StartUp_module) {
138 Py_XDECREF(StartUp_module);
143 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
147 Dmsg0(100, "In set_bacula_events.\n");
148 if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
151 JobStart_method = find_method(eObject, JobStart_method, "JobStart");
152 JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
153 Exit_method = find_method(eObject, Exit_method, "Exit");
160 /* Write text to daemon output */
161 static PyObject *bacula_write(PyObject *self, PyObject *args)
164 if (!PyArg_ParseTuple(args, "s:write", &text)) {
168 Jmsg(NULL, M_INFO, 0, "%s", text);
176 * Check that a method exists and is callable.
178 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
180 Py_XDECREF(method); /* release old method if any */
181 method = PyObject_GetAttrString(eventsObject, (char *)name);
182 if (method == NULL) {
183 Dmsg1(000, "Python method %s not found\n", name);
184 } else if (PyCallable_Check(method) == 0) {
185 Dmsg1(000, "Python object %s found but not a method.\n", name);
189 Dmsg1(100, "Got method %s\n", name);
196 * Generate and process a Bacula event by importing a Python
197 * module and running it.
199 * Returns: 0 if Python not configured or module not found
203 int generate_daemon_event(JCR *jcr, const char *event)
207 PyObject *result = NULL;
209 if (!StartUp_module) {
210 Dmsg0(100, "No startup module.\n");
214 Dmsg1(100, "event=%s\n", event);
215 PyEval_AcquireLock();
216 if (strcmp(event, "JobStart") == 0) {
217 if (!JobStart_method) {
221 /* Create JCR argument to send to function */
222 pJob = (PyObject *)PyObject_New(JobObject, &JobType);
224 Jmsg(jcr, M_ERROR, 0, "Could not create Python Job Object.\n");
227 ((JobObject *)pJob)->jcr = jcr;
228 bstrncpy(jcr->event, event, sizeof(jcr->event));
229 result = PyObject_CallFunction(JobStart_method, "O", pJob);
230 jcr->event[0] = 0; /* no event in progress */
231 if (result == NULL) {
232 JobStart_method = NULL;
233 if (PyErr_Occurred()) {
235 Dmsg0(000, "Python JobStart error.\n");
237 Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
241 jcr->Python_job = (void *)pJob;
245 } else if (strcmp(event, "JobEnd") == 0) {
246 if (!JobEnd_method || !jcr->Python_job) {
247 stat = 0; /* probably already here */
250 bstrncpy(jcr->event, event, sizeof(jcr->event));
251 Dmsg1(100, "Call daemon event=%s\n", event);
252 result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_job);
253 jcr->event[0] = 0; /* no event in progress */
254 if (result == NULL) {
255 if (PyErr_Occurred()) {
257 Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
259 JobEnd_method = NULL;
261 Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
265 } else if (strcmp(event, "Exit") == 0) {
270 result = PyObject_CallFunction(Exit_method, NULL);
271 if (result == NULL) {
276 Jmsg1(jcr, M_ABORT, 0, "Unknown Python daemon event %s\n", event);
281 Py_XDECREF((PyObject *)jcr->Python_job);
282 jcr->Python_job = NULL;
283 Py_XDECREF((PyObject *)jcr->Python_events);
284 jcr->Python_events = NULL;
289 PyEval_ReleaseLock();
296 * No Python configured -- create external entry points and
297 * dummy routines so that library code can call this without
298 * problems even if it is not configured.
300 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
301 void init_python_interpreter(const char *progname, const char *scripts,
302 const char *module) { }
303 void term_python_interpreter() { }
305 #endif /* HAVE_PYTHON */