3 * Bacula common code library interface to Python
5 * Kern Sibbald, November MMIV
11 Copyright (C) 2004-2006 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 /* Forward referenced subroutines */
34 static void init_python_lock();
35 static void term_python_lock();
39 extern char *configfile;
41 /* Imported subroutines */
42 //extern PyMethodDef JobMethods[];
43 extern PyObject *job_getattr(PyObject *self, char *attrname);
44 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
46 static PyObject *bacula_module = NULL; /* We create this */
47 static PyObject *StartUp_module = NULL; /* We import this */
49 /* These are the daemon events or methods that are defined */
50 static PyObject *JobStart_method = NULL;
51 static PyObject *JobEnd_method = NULL;
52 static PyObject *Exit_method = NULL;
54 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
55 static PyObject *bacula_write(PyObject *self, PyObject *args);
57 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
59 /* Define Bacula daemon method entry points */
60 static PyMethodDef BaculaMethods[] = {
61 {"set_events", set_bacula_events, METH_VARARGS, "Define Bacula events."},
62 {"write", bacula_write, METH_VARARGS, "Write output."},
63 {NULL, NULL, 0, NULL} /* last item */
66 static char my_version[] = VERSION " " BDATE;
69 * This is a Bacula Job type as defined in Python. We store a pointer
70 * to the jcr. That is all we need, but the user's script may keep
71 * local data attached to this.
73 typedef struct s_JobObject {
78 static PyTypeObject JobType = {
79 PyObject_HEAD_INIT(NULL)
80 /* Other items filled in in code below */
83 /* Return the JCR pointer from the JobObject */
84 JCR *get_jcr_from_PyObject(PyObject *self)
89 return ((JobObject *)self)->jcr;
93 /* Start the interpreter */
94 void init_python_interpreter(const char *progname, const char *scripts,
99 if (!scripts || scripts[0] == 0) {
100 Dmsg1(100, "No script dir. prog=%s\n", module);
103 Dmsg2(100, "Script dir=%s prog=%s\n", scripts, module);
105 Py_SetProgramName((char *)progname);
107 PyEval_InitThreads();
108 bacula_module = Py_InitModule("bacula", BaculaMethods);
109 PyModule_AddStringConstant(bacula_module, "Name", my_name);
110 PyModule_AddStringConstant(bacula_module, "Version", my_version);
111 PyModule_AddStringConstant(bacula_module, "ConfigFile", configfile);
112 PyModule_AddStringConstant(bacula_module, "WorkingDir", (char *)working_directory);
113 if (!bacula_module) {
114 Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python\n"));
116 bsnprintf(buf, sizeof(buf), "import sys\n"
117 "sys.path.append('%s')\n", scripts);
118 if (PyRun_SimpleString(buf) != 0) {
119 Jmsg1(NULL, M_ERROR_TERM, 0, _("Could not Run Python string %s\n"), buf);
122 /* Explicitly set values we want */
123 JobType.tp_name = "Bacula.Job";
124 JobType.tp_basicsize = sizeof(JobObject);
125 JobType.tp_flags = Py_TPFLAGS_DEFAULT;
126 JobType.tp_doc = "Bacula Job object";
127 JobType.tp_getattr = job_getattr;
128 JobType.tp_setattr = job_setattr;
130 if (PyType_Ready(&JobType) != 0) {
131 Jmsg0(NULL, M_ERROR_TERM, 0, _("Could not initialize Python Job type.\n"));
134 StartUp_module = PyImport_ImportModule((char *)module);
135 if (!StartUp_module) {
136 Emsg2(M_ERROR, 0, _("Could not import Python script %s/%s. Python disabled.\n"),
138 if (PyErr_Occurred()) {
140 Dmsg0(000, "Python Import error.\n");
143 PyEval_ReleaseLock();
148 void term_python_interpreter()
150 if (StartUp_module) {
151 Py_XDECREF(StartUp_module);
157 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
161 Dmsg0(100, "In set_bacula_events.\n");
162 if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
165 JobStart_method = find_method(eObject, JobStart_method, "JobStart");
166 JobEnd_method = find_method(eObject, JobEnd_method, "JobEnd");
167 Exit_method = find_method(eObject, Exit_method, "Exit");
174 /* Write text to daemon output */
175 static PyObject *bacula_write(PyObject *self, PyObject *args)
178 if (!PyArg_ParseTuple(args, "s:write", &text)) {
182 Jmsg(NULL, M_INFO, 0, "%s", text);
190 * Check that a method exists and is callable.
192 PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
194 Py_XDECREF(method); /* release old method if any */
195 method = PyObject_GetAttrString(eventsObject, (char *)name);
196 if (method == NULL) {
197 Dmsg1(000, "Python method %s not found\n", name);
198 } else if (PyCallable_Check(method) == 0) {
199 Dmsg1(000, "Python object %s found but not a method.\n", name);
203 Dmsg1(100, "Got method %s\n", name);
210 * Generate and process a Bacula event by importing a Python
211 * module and running it.
213 * Returns: 0 if Python not configured or module not found
217 int generate_daemon_event(JCR *jcr, const char *event)
221 PyObject *result = NULL;
223 if (!StartUp_module) {
224 Dmsg0(100, "No startup module.\n");
228 Dmsg1(100, "event=%s\n", event);
230 // PyEval_AcquireLock();
231 if (strcmp(event, "JobStart") == 0) {
232 if (!JobStart_method) {
236 /* Create JCR argument to send to function */
237 pJob = (PyObject *)PyObject_New(JobObject, &JobType);
239 Jmsg(jcr, M_ERROR, 0, _("Could not create Python Job Object.\n"));
242 ((JobObject *)pJob)->jcr = jcr;
243 bstrncpy(jcr->event, event, sizeof(jcr->event));
244 result = PyObject_CallFunction(JobStart_method, "O", pJob);
245 jcr->event[0] = 0; /* no event in progress */
246 if (result == NULL) {
247 JobStart_method = NULL;
248 if (PyErr_Occurred()) {
250 Dmsg0(000, "Python JobStart error.\n");
252 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
256 jcr->Python_job = (void *)pJob;
260 } else if (strcmp(event, "JobEnd") == 0) {
261 if (!JobEnd_method || !jcr->Python_job) {
262 stat = 0; /* probably already here */
265 bstrncpy(jcr->event, event, sizeof(jcr->event));
266 Dmsg1(100, "Call daemon event=%s\n", event);
267 result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_job);
268 jcr->event[0] = 0; /* no event in progress */
269 if (result == NULL) {
270 if (PyErr_Occurred()) {
272 Dmsg2(000, "Python JobEnd error. job=%p JobId=%d\n", jcr->Python_job,
274 JobEnd_method = NULL;
276 Jmsg(jcr, M_ERROR, 0, _("Python function \"%s\" not found.\n"), event);
280 } else if (strcmp(event, "Exit") == 0) {
285 result = PyObject_CallFunction(Exit_method, NULL);
286 if (result == NULL) {
291 Jmsg1(jcr, M_ABORT, 0, _("Unknown Python daemon event %s\n"), event);
296 Py_XDECREF((PyObject *)jcr->Python_job);
297 jcr->Python_job = NULL;
298 Py_XDECREF((PyObject *)jcr->Python_events);
299 jcr->Python_events = NULL;
305 // PyEval_ReleaseLock();
309 static brwlock_t python_rwlock;
311 static void init_python_lock()
314 if ((errstat=rwl_init(&python_rwlock)) != 0) {
316 Emsg1(M_ABORT, 0, _("Unable to initialize the Python lock. ERR=%s\n"),
317 be.strerror(errstat));
322 static void term_python_lock()
324 rwl_destroy(&python_rwlock);
327 /* This applies to a drive and to Volumes */
331 if ((errstat=rwl_writelock(&python_rwlock)) != 0) {
333 Emsg2(M_ABORT, 0, "Python rwl_writelock failure. stat=%d: ERR=%s\n",
334 errstat, be.strerror(errstat));
341 if ((errstat=rwl_writeunlock(&python_rwlock)) != 0) {
343 Emsg2(M_ABORT, 0, "Python rwl_writeunlock failure. stat=%d: ERR=%s\n",
344 errstat, be.strerror(errstat));
352 * No Python configured -- create external entry points and
353 * dummy routines so that library code can call this without
354 * problems even if it is not configured.
356 int generate_daemon_event(JCR *jcr, const char *event) { return 0; }
357 void init_python_interpreter(const char *progname, const char *scripts,
358 const char *module) { }
359 void term_python_interpreter() { }
361 #endif /* HAVE_PYTHON */