]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
- Fix new Python code to work for Director.
authorKern Sibbald <kern@sibbald.com>
Tue, 19 Apr 2005 16:49:55 +0000 (16:49 +0000)
committerKern Sibbald <kern@sibbald.com>
Tue, 19 Apr 2005 16:49:55 +0000 (16:49 +0000)
- Move lib/python.c to lib/pythonlib.c so that debug output
  is easier to read (can distinguish lib from dird, ...).

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1937 91ce42f0-d328-0410-95d8-f526ca767f89

15 files changed:
bacula/examples/python/DirStartUp.py [new file with mode: 0644]
bacula/examples/python/FDStartUp.py [new file with mode: 0644]
bacula/examples/python/SDStartUp.py [new file with mode: 0644]
bacula/src/dird/dird.c
bacula/src/dird/job.c
bacula/src/dird/python.c
bacula/src/dird/ua_cmds.c
bacula/src/filed/filed.c
bacula/src/filed/python.c
bacula/src/jcr.h
bacula/src/lib/Makefile.in
bacula/src/lib/jcr.c
bacula/src/lib/pythonlib.c [moved from bacula/src/lib/python.c with 78% similarity]
bacula/src/stored/python.c
bacula/src/stored/stored.c

diff --git a/bacula/examples/python/DirStartUp.py b/bacula/examples/python/DirStartUp.py
new file mode 100644 (file)
index 0000000..2a810f4
--- /dev/null
@@ -0,0 +1,90 @@
+#
+# Bacula Python interface script
+#
+
+# You must import both sys and bacula
+import sys, bacula
+
+# This is the list of Bacula daemon events that you
+#  can receive.
+class BaculaEvents:
+  def __init__(self):
+     # Called here when a new Bacula Events class is
+     #  is created. Normally not used 
+     noop = 1
+
+  def JobStart(self, job):
+     """
+       Called here when a new job is started. If you want
+       to do anything with the Job, you must register
+       events you want to receive.
+     """
+     events = JobEvents()         # create instance of Job class
+     events.job = job             # save Bacula's job pointer
+     job.set_events(events)       # register events desired
+     sys.stderr = events          # send error output to Bacula
+     sys.stdout = events          # send stdout to Bacula
+     jobid = job.get("JobId"); client = job.get("Client"); 
+     numvols = job.get("NumVols") 
+     job.set(JobReport="Python StartJob: JobId=%d Client=%s NumVols=%d\n" % (jobid,client,numvols))
+     return 1
+
+  # Bacula Job is going to terminate
+  def JobEnd(self, job):    
+     jobid = job.get("JobId")
+     client = job.get("Client") 
+     job.set(JobReport="Python EndJob output: JobId=%d Client=%s.\n" % (jobid, client))
+     if (jobid < 2) :
+        startid = job.run("run kernsave")
+        print "Python started new Job: jobid=", startid
+     return 1
+
+  # Called here when the Bacula daemon is going to exit
+  def Exit(self, job):
+      print "Daemon exiting."
+     
+bacula.set_events(BaculaEvents()) # register daemon events desired
+
+"""
+  There are the Job events that you can receive.
+"""
+class JobEvents:
+  def __init__(self):
+     # Called here when you instantiate the Job. Not
+     # normally used
+     noop = 1
+
+  def NewVolume(self, job):
+     jobid = job.get("JobId")
+     client = job.get("Client") 
+     numvol = job.get("NumVols");
+     print "JobId=%d Client=%s NumVols=%d" % (jobid, client, numvol)
+     job.set(JobReport="Python before New Volume set for Job.\n") 
+     job.set(VolumeName="TestA-001")
+     job.set(JobReport="Python after New Volume set for Job.\n") 
+     return 1
+
+
+  # Pass output back to Bacula
+  def write(self, text):
+     self.job.write(text)
+
+  # Open file to be backed up. file is the filename
+  def open(self, file):
+     print "Open %s called" % file
+     self.fd = open('m.py', 'rb')
+     jobid = self.job.get("JobId")
+     print "Open: JobId=%d" % jobid
+     print "name=%s" % bacula.name
+
+  # Read file data into Bacula memory buffer (mem)
+  #  return length read. 0 => EOF, -1 => error
+  def read(self, mem):
+     print "Read called\n"
+     len = self.fd.readinto(mem)
+     print "Read %s bytes into mem.\n" % len
+     return len
+
+  # Close file
+  def close(self):
+     self.fd.close()
diff --git a/bacula/examples/python/FDStartUp.py b/bacula/examples/python/FDStartUp.py
new file mode 100644 (file)
index 0000000..2fe0fb2
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# Bacula Python interface script
+#
+
+# You must import both sys and bacula
+import sys, bacula
+
+# This is the list of Bacula daemon events that you
+#  can receive.
+class BaculaEvents:
+  def __init__(self):
+     # Called here when a new Bacula Events class is
+     #  is created. Normally not used 
+     noop = 1
+
+  def JobStart(self, job):
+     """
+       Called here when a new job is started. If you want
+       to do anything with the Job, you must register
+       events you want to receive.
+     """
+     events = JobEvents()         # create instance of Job class
+     events.job = job             # save Bacula's job pointer
+     job.set_events(events)       # register events desired
+     sys.stderr = events          # send error output to Bacula
+     sys.stdout = events          # send stdout to Bacula
+     jobid = job.get("JobId")
+     client = job.get("Client")
+     numvols = job.get("NumVols") 
+     job.set(JobReport="Python StartJob: JobId=%d Client=%s NumVols=%d\n" % (jobid,client,numvols))
+     return 1
+
+  # Bacula Job is going to terminate
+  def JobEnd(self, job):    
+     jobid = job.get("JobId")
+     client = job.get("Client") 
+     job.set(JobReport="Python EndJob output: JobId=%d Client=%s.\n" % (jobid, client))
+     if (jobid < 2) :
+        startid = job.run("run kernsave")
+        print "Python started new Job: jobid=", startid
+     return 1
+
+  # Called here when the Bacula daemon is going to exit
+  def Exit(self, job):
+      noop = 1
+     
+bacula.set_events(BaculaEvents()) # register daemon events desired
+
+"""
+  There are the Job events that you can receive.
+"""
+class JobEvents:
+  def __init__(self):
+     # Called here when you instantiate the Job. Not
+     # normally used
+     noop = 1
+
+  def NewVolume(self, job):
+     jobid = job.get("JobId")
+     print "JobId=", jobid
+     client = job.get("Client") 
+     print "Client=" + client
+     numvol = job.get("NumVols");
+     print "NumVols=", numvol
+     job.set(JobReport="Python New Volume set for Job.\n") 
+     job.set(VolumeName="TestA-001")
+     return 1
+
+
+  # Pass output back to Bacula
+  def write(self, text):
+     self.job.write(text)
+
+  # Open file to be backed up. file is the filename
+  def open(self, file):
+     print "Open %s called" % file
+     self.fd = open('m.py', 'rb')
+     jobid = self.job.get("JobId")
+     print "Open: JobId=%d" % jobid
+     print "name=%s" % bacula.name
+
+  # Read file data into Bacula memory buffer (mem)
+  #  return length read. 0 => EOF, -1 => error
+  def read(self, mem):
+     print "Read called\n"
+     len = self.fd.readinto(mem)
+     print "Read %s bytes into mem.\n" % len
+     return len
+
+  # Close file
+  def close(self):
+     self.fd.close()
diff --git a/bacula/examples/python/SDStartUp.py b/bacula/examples/python/SDStartUp.py
new file mode 100644 (file)
index 0000000..2fe0fb2
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# Bacula Python interface script
+#
+
+# You must import both sys and bacula
+import sys, bacula
+
+# This is the list of Bacula daemon events that you
+#  can receive.
+class BaculaEvents:
+  def __init__(self):
+     # Called here when a new Bacula Events class is
+     #  is created. Normally not used 
+     noop = 1
+
+  def JobStart(self, job):
+     """
+       Called here when a new job is started. If you want
+       to do anything with the Job, you must register
+       events you want to receive.
+     """
+     events = JobEvents()         # create instance of Job class
+     events.job = job             # save Bacula's job pointer
+     job.set_events(events)       # register events desired
+     sys.stderr = events          # send error output to Bacula
+     sys.stdout = events          # send stdout to Bacula
+     jobid = job.get("JobId")
+     client = job.get("Client")
+     numvols = job.get("NumVols") 
+     job.set(JobReport="Python StartJob: JobId=%d Client=%s NumVols=%d\n" % (jobid,client,numvols))
+     return 1
+
+  # Bacula Job is going to terminate
+  def JobEnd(self, job):    
+     jobid = job.get("JobId")
+     client = job.get("Client") 
+     job.set(JobReport="Python EndJob output: JobId=%d Client=%s.\n" % (jobid, client))
+     if (jobid < 2) :
+        startid = job.run("run kernsave")
+        print "Python started new Job: jobid=", startid
+     return 1
+
+  # Called here when the Bacula daemon is going to exit
+  def Exit(self, job):
+      noop = 1
+     
+bacula.set_events(BaculaEvents()) # register daemon events desired
+
+"""
+  There are the Job events that you can receive.
+"""
+class JobEvents:
+  def __init__(self):
+     # Called here when you instantiate the Job. Not
+     # normally used
+     noop = 1
+
+  def NewVolume(self, job):
+     jobid = job.get("JobId")
+     print "JobId=", jobid
+     client = job.get("Client") 
+     print "Client=" + client
+     numvol = job.get("NumVols");
+     print "NumVols=", numvol
+     job.set(JobReport="Python New Volume set for Job.\n") 
+     job.set(VolumeName="TestA-001")
+     return 1
+
+
+  # Pass output back to Bacula
+  def write(self, text):
+     self.job.write(text)
+
+  # Open file to be backed up. file is the filename
+  def open(self, file):
+     print "Open %s called" % file
+     self.fd = open('m.py', 'rb')
+     jobid = self.job.get("JobId")
+     print "Open: JobId=%d" % jobid
+     print "name=%s" % bacula.name
+
+  # Read file data into Bacula memory buffer (mem)
+  #  return length read. 0 => EOF, -1 => error
+  def read(self, mem):
+     print "Read called\n"
+     len = self.fd.readinto(mem)
+     print "Read %s bytes into mem.\n" % len
+     return len
+
+  # Close file
+  def close(self):
+     self.fd.close()
index a6f072d8b7c523e6610a32dcafdc5b65cd76d34d..c1c05479453db6dcf727433a5a32346ea177ce2c 100644 (file)
@@ -222,8 +222,8 @@ int main (int argc, char *argv[])
 
    init_console_msg(working_directory);
 
-   init_python_interpreter(director->hdr.name, director->scripts_directory ?
-      director->scripts_directory : ".", "DirStartUp");
+   init_python_interpreter(director->hdr.name, director->scripts_directory
+       "DirStartUp");
 
    set_thread_concurrency(director->MaxConcurrentJobs * 2 +
       4 /* UA */ + 4 /* sched+watchdog+jobsvr+misc */);
@@ -255,12 +255,13 @@ int main (int argc, char *argv[])
 /* Cleanup and then exit */
 static void terminate_dird(int sig)
 {
-   static int already_here = FALSE;
+   static bool already_here = false;
 
    if (already_here) {                /* avoid recursive temination problems */
       exit(1);
    }
-   already_here = TRUE;
+   already_here = true;
+   generate_daemon_event(NULL, "Exit");
    write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
    delete_pid_file(director->pid_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
 // signal(SIGCHLD, SIG_IGN);          /* don't worry about children now */
index bf9a4ea8e40332686f34f61679fb5f44c98c463c..a42b66bc24f2ed961445a7d69423699abbd5dd1b 100644 (file)
@@ -93,7 +93,6 @@ JobId_t run_job(JCR *jcr)
    }
    jcr->term_wait_inited = true;
 
-   generate_daemon_event(jcr, "StartJob");
 
    /*
     * Open database
@@ -113,6 +112,7 @@ JobId_t run_job(JCR *jcr)
    }
    Dmsg0(50, "DB opened\n");
 
+
    /*
     * Create Job record
     */
@@ -124,10 +124,11 @@ JobId_t run_job(JCR *jcr)
       goto bail_out;
    }
    JobId = jcr->JobId = jcr->jr.JobId;
-
    Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
        jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
 
+   generate_daemon_event(jcr, "JobStart");
+
    if (!get_or_create_client_record(jcr)) {
       goto bail_out;
    }
index e717b1271e8eee2d6ef629f8380ec8a263599553..f5445366e8228f1581faf6751d78bdcfc87d4db3 100644 (file)
 #include <Python.h>
 
 extern JCR *get_jcr_from_PyObject(PyObject *self);
-extern PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name);
+extern PyObject *find_method(PyObject *eventsObject, PyObject *method, 
+         const char *name);
 
-static PyObject *jcr_get(PyObject *self, PyObject *args);
+static PyObject *job_get(PyObject *self, PyObject *args);
 static PyObject *jcr_write(PyObject *self, PyObject *args);
 static PyObject *jcr_set(PyObject *self, PyObject *args, PyObject *keyw);
-static PyObject *set_jcr_events(PyObject *self, PyObject *args);
+static PyObject *set_job_events(PyObject *self, PyObject *args);
 static PyObject *jcr_run(PyObject *self, PyObject *args);
 
 /* Define Job entry points */
 PyMethodDef JobMethods[] = {
-    {"get", jcr_get, METH_VARARGS, "Get Job variables."},
+    {"get", job_get, METH_VARARGS, "Get Job variables."},
     {"set", (PyCFunction)jcr_set, METH_VARARGS|METH_KEYWORDS,
         "Set Job variables."},
-    {"set_events", set_jcr_events, METH_VARARGS, "Define Job events."},
+    {"set_events", set_job_events, METH_VARARGS, "Define Job events."},
     {"write", jcr_write, METH_VARARGS, "Write output."},
     {"run", (PyCFunction)jcr_run, METH_VARARGS, "Run a Bacula command."},
     {NULL, NULL, 0, NULL}             /* last item */
 };
 
 
-static PyObject *open_method = NULL;
-static PyObject *read_method = NULL;
-static PyObject *close_method = NULL;
-
 struct s_vars {
    const char *name;
    char *fmt;
@@ -85,7 +82,7 @@ static struct s_vars vars[] = {
 };
 
 /* Return Job variables */
-static PyObject *jcr_get(PyObject *self, PyObject *args)
+static PyObject *job_get(PyObject *self, PyObject *args)
 {
    JCR *jcr;
    char *item;
@@ -93,6 +90,7 @@ static PyObject *jcr_get(PyObject *self, PyObject *args)
    int i;
    char buf[10];
 
+   Dmsg0(100, "In jcr_get.\n");
    if (!PyArg_ParseTuple(args, "s:get", &item)) {
       return NULL;
    }
@@ -146,6 +144,8 @@ static PyObject *jcr_set(PyObject *self, PyObject *args, PyObject *keyw)
    char *msg = NULL;
    char *VolumeName = NULL;
    static char *kwlist[] = {"JobReport", "VolumeName", NULL};
+
+   Dmsg0(100, "In jcr_set.\n");
    if (!PyArg_ParseTupleAndKeywords(args, keyw, "|ss:set", kwlist,
         &msg, &VolumeName)) {
       return NULL;
@@ -155,27 +155,39 @@ static PyObject *jcr_set(PyObject *self, PyObject *args, PyObject *keyw)
    if (msg) {
       Jmsg(jcr, M_INFO, 0, "%s", msg);
    }
+
+   if (!VolumeName) {
+      Dmsg1(100, "No VolumeName. Event=%s\n", jcr->event);
+   } else {
+      Dmsg2(100, "Vol=%s Event=%s\n", VolumeName, jcr->event);
+   }
    /* Make sure VolumeName is valid and we are in VolumeName event */
-   if (VolumeName && strcmp("VolumeName", jcr->event) == 0 &&
+   if (VolumeName && strcmp("NewVolume", jcr->event) == 0 &&
        is_volume_name_legal(NULL, VolumeName)) {
       pm_strcpy(jcr->VolumeName, VolumeName);
-   } else {
+      Dmsg1(100, "Set Vol=%s\n", VolumeName);
+   } else if (VolumeName) {
       jcr->VolumeName[0] = 0;
+      Dmsg0(100, "Zap VolumeName.\n");
       return Py_BuildValue("i", 0);  /* invalid volume name */
    }
    return Py_BuildValue("i", 1);
 }
 
-static PyObject *set_jcr_events(PyObject *self, PyObject *args)
+static PyObject *set_job_events(PyObject *self, PyObject *args)
 {
    PyObject *eObject;
+   JCR *jcr;
+
+   Dmsg0(100, "In set_job_events.\n");
    if (!PyArg_ParseTuple(args, "O:set_events_hook", &eObject)) {
       return NULL;
    }
-   Py_XINCREF(eObject);
-   open_method = find_method(eObject, open_method, "open");
-   read_method = find_method(eObject, read_method, "read");
-   close_method = find_method(eObject, close_method, "close");
+   jcr = get_jcr_from_PyObject(self);
+   Py_XDECREF((PyObject *)jcr->Python_events);
+   Py_INCREF(eObject);
+   jcr->Python_events = (void *)eObject;
+
    Py_INCREF(Py_None);
    return Py_None;
 }
@@ -184,6 +196,7 @@ static PyObject *set_jcr_events(PyObject *self, PyObject *args)
 static PyObject *jcr_write(PyObject *self, PyObject *args)
 {
    char *text;
+
    if (!PyArg_ParseTuple(args, "s:write", &text)) {
       return NULL;
    }
@@ -219,22 +232,39 @@ static PyObject *jcr_run(PyObject *self, PyObject *args)
 
 int generate_job_event(JCR *jcr, const char *event)
 {
-#ifdef xxx
-   PyObject *eObject, *method;
+   PyObject *method = NULL;
+   PyObject *Job = (PyObject *)jcr->Python_job;
+   PyObject *result = NULL;
+   int stat = 0;
+
+   if (!Job) {
+      return 0;
+   }
+
    PyEval_AcquireLock();
 
-   method = find_method(eObject, method, event);
+   PyObject *events = (PyObject *)jcr->Python_events;
+   method = find_method(events, method, event);
+   if (!method) {
+      goto bail_out;
+   }
 
-   PyObject *result = PyObject_CallFunction(method, "s", "m.py");
+   bstrncpy(jcr->event, event, sizeof(jcr->event));
+   result = PyObject_CallFunction(method, "O", Job);
+   jcr->event[0] = 0;             /* no event in progress */
    if (result == NULL) {
-      PyErr_Print();
-      PyErr_Clear();
+      if (PyErr_Occurred()) {
+         PyErr_Print();
+         Dmsg1(000, "Error in Python method %s\n", event);
+      }
+   } else {
+      stat = 1;
    }
    Py_XDECREF(result);
 
+bail_out:
    PyEval_ReleaseLock();
-#endif
-   return 1;
+   return stat;
 }
 
 #else
index 7125d4e57f6940cdcb45afc427ce0e4ad1b673fe..5c0da912ada4c87cc7b84e2c0131bf5ca5328653 100644 (file)
@@ -571,8 +571,8 @@ static int python_cmd(UAContext *ua, const char *cmd)
 {
    if (strcasecmp(ua->argk[1], _("restart")) == 0) {
       term_python_interpreter();
-      init_python_interpreter(director->hdr.name, director->scripts_directory ?
-         director->scripts_directory : ".", "DirStartUp");
+      init_python_interpreter(director->hdr.name, 
+         director->scripts_directory, "DirStartUp");
       bsendmsg(ua, _("Python interpreter restarted.\n"));
    } else {
       bsendmsg(ua, _("Nothing done.\n"));
index 9fdd1983f762708191cf46207ae1fa13c3351a4e..bcfa65c5ed6e287b6a8d1d167a5fdabd63505547 100644 (file)
@@ -230,8 +230,7 @@ int main (int argc, char *argv[])
    me += 1000000;
 #endif
 
-   init_python_interpreter(me->hdr.name, me->scripts_directory ?
-         me->scripts_directory : ".", "FDStartUp");
+   init_python_interpreter(me->hdr.name, me->scripts_directory, "FDStartUp");
 
    set_thread_concurrency(10);
 
index ea7c0cdb6dc3a3c25057a6c87c4ef882f032e10f..3af306a47790204bf8a2ca91ff43f989f1061abe 100644 (file)
@@ -36,7 +36,8 @@
 #include <Python.h>
 
 extern JCR *get_jcr_from_PyObject(PyObject *self);
-extern PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name);
+extern PyObject *find_method(PyObject *eventsObject, PyObject *method, 
+          const char *name);
 
 static PyObject *jcr_get(PyObject *self, PyObject *args);
 static PyObject *jcr_write(PyObject *self, PyObject *args);
index 6cccbdcd029bb53473ed7b2c77a90e0d42fd011a..271655b635b67f9f74b3c137b35dd1dd618af27b 100644 (file)
@@ -143,7 +143,8 @@ struct JCR {
    bool prefix_links;                 /* Prefix links with Where path */
    bool gui;                          /* set if gui using console */
    bool authenticated;                /* set when client authenticated */
-   void *Python_jcr;                  /* Python Job Object */
+   void *Python_job;                  /* Python Job Object */
+   void *Python_events;               /* Python Events Object */
 
    /* Daemon specific part of JCR */
    /* This should be empty in the library */
index 47b9c2d2d083c1fd02015ad1c3d77d1cf3628f87..df440b5e9ff7ce39d8f28f0b74e74dfa9c3bce83 100644 (file)
@@ -29,7 +29,7 @@ LIBSRCS = alloc.c attr.c base64.c berrno.c bsys.c bget_msg.c \
          queue.c res.c rwlock.c scan.c serial.c sha1.c \
          semlock.c signal.c smartall.c tree.c \
          util.c var.c watchdog.c workq.c btimers.c \
-         address_conf.c python.c 
+         address_conf.c pythonlib.c 
 
 
 LIBOBJS = alloc.o attr.o base64.o berrno.o bsys.o bget_msg.o \
@@ -41,7 +41,7 @@ LIBOBJS = alloc.o attr.o base64.o berrno.o bsys.o bget_msg.o \
          queue.o res.o rwlock.o scan.o serial.o sha1.o \
          semlock.o signal.o smartall.o tree.o \
          util.o var.o watchdog.o workq.o btimers.o \
-         address_conf.o python.o
+         address_conf.o pythonlib.o
 
 
 EXTRAOBJS = @OBJLIST@
@@ -72,7 +72,7 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
        cd $(topdir) \
          && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
 
-python.o: python.c
+pythonlib.o: pythonlib.c
        $(CXX) $(DEFS) $(DEBUG) -c $(WCFLAGS) $(CPPFLAGS) $(python) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
 
 rwlock_test:
index 44a0e484883d36404e842fa5a60418374a80c35e..709a30d9b2677405e458c6f1b8ee3343eef3f7f1 100755 (executable)
@@ -354,9 +354,6 @@ void free_jcr(JCR *jcr)
 #endif
 
    dequeue_messages(jcr);
-   if (jcr->JobId != 0) {
-      generate_daemon_event(jcr, "JobEnd");
-   }
    lock_jcr_chain();
    jcr->use_count--;                  /* decrement use count */
    if (jcr->use_count < 0) {
@@ -369,6 +366,14 @@ void free_jcr(JCR *jcr)
       Dmsg2(3400, "free_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
       return;
    }
+
+   /* 
+    * At this point, we are actually releasing the JCR, which
+    *  means that the job is complete.
+    */
+   if (jcr->JobId != 0) {
+      generate_daemon_event(jcr, "JobEnd");
+   }
    remove_jcr(jcr);                   /* remove Jcr from chain */
    unlock_jcr_chain();
 
similarity index 78%
rename from bacula/src/lib/python.c
rename to bacula/src/lib/pythonlib.c
index cfc3ebde90f25af4ade28e66e3dd43a632339a30..7ad103099564f6472bdb828c3f9cc703ac2d8d60 100644 (file)
@@ -36,6 +36,9 @@
 #undef _POSIX_C_SOURCE
 #include <Python.h>
 
+/* Imported subroutines */
+extern PyMethodDef JobMethods[];
+
 static PyObject *bacula_module = NULL;    /* We create this */
 static PyObject *StartUp_module = NULL;   /* We import this */
 
@@ -44,11 +47,10 @@ static PyObject *JobStart_method = NULL;
 static PyObject *JobEnd_method = NULL;
 static PyObject *Exit_method = NULL;
 
-
 static PyObject *set_bacula_events(PyObject *self, PyObject *args);
 static PyObject *bacula_write(PyObject *self, PyObject *args);
 
-PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name);
+PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name);
 
 /* Define Bacula daemon method entry points */
 static PyMethodDef BaculaMethods[] = {
@@ -63,16 +65,16 @@ static PyMethodDef BaculaMethods[] = {
  *   to the jcr. That is all we need, but the user's script may keep
  *   local data attached to this. 
  */
-typedef struct JCRObject {
+typedef struct s_JobObject {
     PyObject_HEAD
     JCR *jcr;
-} JCRObject;
+} JobObject;
 
-static PyTypeObject JCRType = {
+static PyTypeObject JobType = {
     PyObject_HEAD_INIT(NULL)
     0,                         /*ob_size*/
     "bacula.jcr",              /*tp_name*/
-    sizeof(JCRObject),         /*tp_basicsize*/
+    sizeof(JobObject),         /*tp_basicsize*/
     0,                         /*tp_itemsize*/
     0,                         /*tp_dealloc*/
     0,                         /*tp_print*/
@@ -90,14 +92,14 @@ static PyTypeObject JCRType = {
     0,                         /*tp_setattro*/
     0,                         /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT, /*tp_flags*/
-    "JCR objects",             /* tp_doc */
+    "Job objects",             /* tp_doc */
     0,                         /* tp_traverse */
     0,                         /* tp_clear */
     0,                         /* tp_richcompare */
     0,                         /* tp_weaklistoffset */
     0,                         /* tp_iter */
     0,                         /* tp_iternext */
-    0,                         /* tp_methods */
+    JobMethods,                /* tp_methods */
     0,                         /* tp_members */
     0,                         /* tp_getset */
     0,                         /* tp_base */
@@ -110,10 +112,10 @@ static PyTypeObject JCRType = {
     0,                         /* tp_new */
 };
 
-/* Return the JCR pointer from the JCRObject */
+/* Return the JCR pointer from the JobObject */
 JCR *get_jcr_from_PyObject(PyObject *self)
 {
-   return ((JCRObject *)self)->jcr;
+   return ((JobObject *)self)->jcr;
 }
 
 
@@ -122,28 +124,36 @@ void init_python_interpreter(const char *progname, const char *scripts,
     const char *module)
 {
    char buf[MAXSTRING];
+
+   if (!scripts || scripts[0] == 0) {
+      return;
+   }
+
    Py_SetProgramName((char *)progname);
    Py_Initialize();
    PyEval_InitThreads();
    bacula_module = Py_InitModule("bacula", BaculaMethods);
    if (!bacula_module) {
-      Jmsg(NULL, M_ERROR_TERM, 0, "Could not initialize Python\n");
+      Jmsg0(NULL, M_ERROR_TERM, 0, "Could not initialize Python\n");
    }
    bsnprintf(buf, sizeof(buf), "import sys\n"
             "sys.path.append('%s')\n", scripts);
    if (PyRun_SimpleString(buf) != 0) {
-      Jmsg(NULL, M_ERROR_TERM, 0, "Could not Run Python string %s\n", buf);
+      Jmsg1(NULL, M_ERROR_TERM, 0, "Could not Run Python string %s\n", buf);
    }   
-   JCRType.tp_methods = BaculaMethods;
-   if(PyType_Ready(&JCRType) != 0) {
-      Jmsg(NULL, M_ERROR_TERM, 0, "Could not initialize Python Job type.\n");
+   JobType.tp_methods = JobMethods;
+   if(PyType_Ready(&JobType) != 0) {
+      Jmsg0(NULL, M_ERROR_TERM, 0, "Could not initialize Python Job type.\n");
       PyErr_Print();
    }   
    StartUp_module = PyImport_ImportModule((char *)module);
    if (!StartUp_module) {
-      Jmsg(NULL, M_ERROR_TERM, 0, "Could not import script %s/%s.\n",
+      Emsg2(M_ERROR, 0, "Could not import Python script %s/%s. Python disabled.\n",
            scripts, module);
-      PyErr_Clear();
+      if (PyErr_Occurred()) {
+         PyErr_Print();
+         Dmsg0(000, "Python Import error.\n");
+      }
    }
    PyEval_ReleaseLock();
 }
@@ -151,13 +161,17 @@ void init_python_interpreter(const char *progname, const char *scripts,
 
 void term_python_interpreter()
 {
-   Py_XDECREF(StartUp_module);
-   Py_Finalize();
+   if (StartUp_module) {
+      Py_XDECREF(StartUp_module);
+      Py_Finalize();
+   }
 }
 
 static PyObject *set_bacula_events(PyObject *self, PyObject *args)
 {
    PyObject *eObject;
+
+   Dmsg0(100, "In set_bacula_events.\n");
    if (!PyArg_ParseTuple(args, "O:set_bacula_events", &eObject)) {
       return NULL;
    }
@@ -188,10 +202,10 @@ static PyObject *bacula_write(PyObject *self, PyObject *args)
 /*
  * Check that a method exists and is callable.
  */
-PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name)
+PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name)
 {
    Py_XDECREF(method);             /* release old method if any */
-   method = PyObject_GetAttrString(eventsObject, name);
+   method = PyObject_GetAttrString(eventsObject, (char *)name);
    if (method == NULL) {
        Dmsg1(000, "Python method %s not found\n", name);
    } else if (PyCallable_Check(method) == 0) {
@@ -199,7 +213,7 @@ PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name)
        Py_XDECREF(method);
        method = NULL;
    } else {
-       Dmsg1(000, "Got method %s\n", name);
+       Dmsg1(100, "Got method %s\n", name);
    }
    return method; 
 }
@@ -215,10 +229,14 @@ PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name)
  */
 int generate_daemon_event(JCR *jcr, const char *event)
 {
-   PyObject *pJCR;
+   PyObject *pJob;
    int stat = -1;
    PyObject *result = NULL;
 
+   if (!StartUp_module) {
+      return 0;
+   }
+
    PyEval_AcquireLock();
    if (strcmp(event, "JobStart") == 0) {
       if (!JobStart_method) {
@@ -226,50 +244,68 @@ int generate_daemon_event(JCR *jcr, const char *event)
          goto bail_out;
       }
       /* Create JCR argument to send to function */
-      pJCR = (PyObject *)PyObject_New(JCRObject, &JCRType);
-      if (!pJCR) {
-         Jmsg(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
+      pJob = (PyObject *)PyObject_New(JobObject, &JobType);
+      if (!pJob) {
+         Jmsg(jcr, M_ERROR, 0, "Could not create Python Job Object.\n");
          goto bail_out;
       }
-      ((JCRObject *)pJCR)->jcr = jcr;
+      ((JobObject *)pJob)->jcr = jcr;
       bstrncpy(jcr->event, event, sizeof(jcr->event));
-      result = PyObject_CallFunction(JobStart_method, "O", pJCR);
+      result = PyObject_CallFunction(JobStart_method, "O", pJob);
       jcr->event[0] = 0;             /* no event in progress */
       if (result == NULL) {
          JobStart_method = NULL;
          if (PyErr_Occurred()) {
             PyErr_Print();
+            Dmsg0(000, "Python JobStart error.\n");
          }
          Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
-         Py_XDECREF(pJCR);
+         Py_XDECREF(pJob);
          goto bail_out;
       }
-      jcr->Python_jcr = (void *)pJCR;
+      jcr->Python_job = (void *)pJob;
       stat = 1;                       /* OK */
+      goto jobstart_ok;
 
    } else if (strcmp(event, "JobEnd") == 0) {
       if (!JobEnd_method) {
-         Py_XDECREF((PyObject *)jcr->Python_jcr);
          stat = 0;
          goto bail_out;
       }
       bstrncpy(jcr->event, event, sizeof(jcr->event));
-      result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_jcr);
+      result = PyObject_CallFunction(JobEnd_method, "O", jcr->Python_job);
       jcr->event[0] = 0;             /* no event in progress */
       if (result == NULL) {
          JobEnd_method = NULL;
          if (PyErr_Occurred()) {
             PyErr_Print();
+            Dmsg1(000, "Python JobEnd error. JobId=%d\n", jcr->JobId);
          }
          Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found.\n", event);
-         Py_XDECREF((PyObject *)jcr->Python_jcr);
          goto bail_out;
       }
-      Py_XDECREF((PyObject *)jcr->Python_jcr);
       stat = 1;                    /* OK */
+   } else if (strcmp(event, "Exit") == 0) {
+      if (!Exit_method) {
+         stat = 0;
+         goto bail_out;
+      }
+      result = PyObject_CallFunction(JobEnd_method, NULL);
+      if (result == NULL) {
+         goto bail_out;
+      }
+      stat = 1;                    /* OK */
+   } else {
+      Emsg1(M_ABORT, 0, "Unknown Python daemon event %s\n", event);
    }
 
 bail_out:
+   Py_XDECREF((PyObject *)jcr->Python_job);
+   jcr->Python_job = NULL;
+   Py_XDECREF((PyObject *)jcr->Python_events);
+   jcr->Python_events = NULL;
+   /* Fall through */
+jobstart_ok:
    Py_XDECREF(result);
    PyEval_ReleaseLock();
    return stat; 
@@ -304,7 +340,7 @@ bail_out:
           if (!pJCR) {
              Py_DECREF(pArgs);
              Py_DECREF(pModule);
-             Jmsg(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
+             Jmsg0(jcr, M_ERROR, 0, "Could not create JCR Python Object.\n");
              return -1;
           }
           Py_INCREF(pJCR);
@@ -322,15 +358,16 @@ bail_out:
           } else {
              Py_DECREF(pModule);
              PyErr_Print();
-             Jmsg(jcr, M_ERROR, 0, "Error running Python module: %s\n", event);
+             Jmsg1(jcr, M_ERROR, 0, "Error running Python module: %s\n", event);
              return 0;                /* error running function */
           }
           /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
       } else {
          if (PyErr_Occurred()) {
             PyErr_Print();
+            Dmsg1(000, "Python event %s function not callable.\n", event);
          }
-         Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found in module.\n", event);
+         Jmsg1(jcr, M_ERROR, 0, "Python function \"%s\" not found in module.\n", event);
          return -1;                   /* function not found */
       }
       Py_DECREF(pModule);
index 00e95f78ad2c0ee21bf22311a2746e19559c2876..aa9e7e86a1ea64ec40975429e9f5e357e5744bab 100644 (file)
@@ -36,7 +36,8 @@
 #include <Python.h>
 
 extern JCR *get_jcr_from_PyObject(PyObject *self);
-extern PyObject *find_method(PyObject *eventsObject, PyObject *method, char *name);
+extern PyObject *find_method(PyObject *eventsObject, PyObject *method, 
+         const char *name);
 
 static PyObject *jcr_get(PyObject *self, PyObject *args);
 static PyObject *jcr_write(PyObject *self, PyObject *args);
index d45ca8b0d3f99efbc53f3aba9382afa5a865d1b1..0f404349330385f8e160ade0a15c2de14c42f92d 100644 (file)
@@ -208,8 +208,7 @@ int main (int argc, char *argv[])
       Jmsg0(NULL, M_ABORT, 0, _("Volume Session Time is ZERO!\n"));
    }
 
-   init_python_interpreter(me->hdr.name, me->scripts_directory ?
-         me->scripts_directory : ".", "SDStartUp");
+   init_python_interpreter(me->hdr.name, me->scripts_directory, "SDStartUp");
 
    /* Make sure on Solaris we can run concurrent, watch dog + servers + misc */
    set_thread_concurrency(me->max_concurrent_jobs * 2 + 4);