From: Kern Sibbald Date: Fri, 6 May 2005 15:54:59 +0000 (+0000) Subject: - Move test for MaxStartDelay as suggested by Peter. X-Git-Tag: Release-1.38.0~499 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=057b39a9f57bdc65a6d6f6f84cf3d56fe5ec03ca;p=bacula%2Fbacula - Move test for MaxStartDelay as suggested by Peter. - Implement Python methods (I had to read the Python source code). - Implement run() method in Director. - Add Priority and Scheduled time to Job report. - Add JobInit and JobRun events. - Add Priority as Python read/write attribute to Job. - Correct typo in bsmtp reported by Jo. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1999 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/examples/python/DirStartUp.py b/bacula/examples/python/DirStartUp.py index 37eaa28d5c..5a9942b66c 100644 --- a/bacula/examples/python/DirStartUp.py +++ b/bacula/examples/python/DirStartUp.py @@ -21,23 +21,18 @@ class BaculaEvents: """ events = JobEvents() # create instance of Job class events.job = job # save Bacula's job pointer - job.set_events = events # register events desired + job.set_events(events) # register events desired sys.stderr = events # send error output to Bacula sys.stdout = events # send stdout to Bacula jobid = job.JobId; client = job.Client numvols = job.NumVols job.JobReport="Python Dir JobStart: JobId=%d Client=%s NumVols=%d\n" % (jobid,client,numvols) - return 1 # Bacula Job is going to terminate def JobEnd(self, job): jobid = job.JobId client = job.Client - job.JobReport="Python Dir JobEnd 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 + job.JobReport="Python Dir JobEnd output: JobId=%d Status=%s Client=%s.\n" % (jobid, job.JobStatus, client) # Called here when the Bacula daemon is going to exit def Exit(self, job): @@ -54,11 +49,20 @@ class JobEvents: # normally used noop = 1 + def JobInit(self, job): + noop = 1 + if (job.JobId < 2): + startid = job.run("run kernsave") + job.JobReport = "Python started new Job: jobid=%d\n" % startid + + def JobRun(self, job): + noop = 1 + def NewVolume(self, job): jobid = job.JobId client = job.Client numvol = job.NumVols; - print "JobId=%d Client=%s NumVols=%d" % (jobid, client, numvol) + job.JobReport = "JobId=%d Client=%s NumVols=%d" % (jobid, client, numvol) job.JobReport="Python before New Volume set for Job.\n" job.VolumeName="TestA-001" job.JobReport="Python after New Volume set for Job.\n" diff --git a/bacula/examples/python/FDStartUp.py b/bacula/examples/python/FDStartUp.py index d553f2cd9e..0c274c8c0f 100644 --- a/bacula/examples/python/FDStartUp.py +++ b/bacula/examples/python/FDStartUp.py @@ -20,7 +20,7 @@ class BaculaEvents: """ events = JobEvents() # create instance of Job class events.job = job # save Bacula's job pointer - job.set_events = events # register events desired + job.set_events(events) # register events desired sys.stderr = events # send error output to Bacula sys.stdout = events # send stdout to Bacula jobid = job.JobId @@ -33,7 +33,7 @@ class BaculaEvents: jobid = job.JobId client = job.Client job.JobReport="Python FD JobEnd output: JobId=%d Client=%s.\n" % (jobid, client) - return 1 + # Called here when the Bacula daemon is going to exit def Exit(self): diff --git a/bacula/examples/python/SDStartUp.py b/bacula/examples/python/SDStartUp.py index ff6a97b2e5..8430e4f1ce 100644 --- a/bacula/examples/python/SDStartUp.py +++ b/bacula/examples/python/SDStartUp.py @@ -20,7 +20,7 @@ class BaculaEvents: """ events = JobEvents() # create instance of Job class events.job = job # save Bacula's job pointer - job.set_events = events # register events desired + job.set_events(events) # register events desired sys.stderr = events # send error output to Bacula sys.stdout = events # send stdout to Bacula jobid = job.JobId @@ -33,8 +33,8 @@ class BaculaEvents: jobid = job.JobId client = job.Client job.JobReport="Python SD JobEnd output: JobId=%d Client=%s.\n" % (jobid, client) - print "Python SD JobEnd\n" - return 1 +# print "Python SD JobEnd\n" + # Called here when the Bacula daemon is going to exit def Exit(self): diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index f2976ec9ec..39f9ce56d5 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -8,7 +8,7 @@ * Open DB and create records for this job. * Open Message Channel with Storage daemon to tell him a job will be starting. * Open connection with File daemon and pass him commands - * to do the backup. + * to do the backup. * When the File daemon finishes the job, update the DB. * * Version $Id$ @@ -62,17 +62,17 @@ bool do_backup_init(JCR *jcr) switch (jcr->JobLevel) { case L_FULL: if (jcr->full_pool) { - jcr->pool = jcr->full_pool; + jcr->pool = jcr->full_pool; } break; case L_INCREMENTAL: if (jcr->inc_pool) { - jcr->pool = jcr->inc_pool; + jcr->pool = jcr->inc_pool; } break; case L_DIFFERENTIAL: if (jcr->dif_pool) { - jcr->pool = jcr->dif_pool; + jcr->pool = jcr->dif_pool; } break; } @@ -83,18 +83,18 @@ bool do_backup_init(JCR *jcr) /* Try to create the pool */ if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) { Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name, - db_strerror(jcr->db)); - return false; + db_strerror(jcr->db)); + return false; } else { Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name); - if (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */ + if (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */ Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name, - db_strerror(jcr->db)); - return false; - } + db_strerror(jcr->db)); + return false; + } } } - jcr->PoolId = pr.PoolId; /****FIXME**** this can go away */ + jcr->PoolId = pr.PoolId; /****FIXME**** this can go away */ jcr->jr.PoolId = pr.PoolId; if (!get_or_create_fileset_record(jcr, &fsr)) { @@ -115,13 +115,13 @@ bool do_backup_init(JCR *jcr) cmd = edit_job_codes(jcr, cmd, runcmd, ""); Mmsg(ua->cmd, "run %s cloned=yes", cmd); Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd); - parse_ua_args(ua); /* parse command */ - int stat = run_cmd(ua, ua->cmd); - if (stat == 0) { + parse_ua_args(ua); /* parse command */ + int stat = run_cmd(ua, ua->cmd); + if (stat == 0) { Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n")); - } else { + } else { Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat); - } + } } free_ua_context(ua); free_pool_memory(cmd); @@ -134,7 +134,7 @@ bool do_backup_init(JCR *jcr) * Do a backup of the specified FileSet * * Returns: false on failure - * true on success + * true on success */ bool do_backup(JCR *jcr) { @@ -146,7 +146,7 @@ bool do_backup(JCR *jcr) /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %u, Job=%s\n"), - jcr->JobId, jcr->Job); + jcr->JobId, jcr->Job); set_jcr_job_status(jcr, JS_Running); Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel); @@ -215,15 +215,15 @@ bool do_backup(JCR *jcr) /* TLS Requirement */ if (store->tls_enable) { if (store->tls_require) { - tls_need = BNET_TLS_REQUIRED; + tls_need = BNET_TLS_REQUIRED; } else { - tls_need = BNET_TLS_OK; + tls_need = BNET_TLS_OK; } } #endif bnet_fsend(fd, storaddr, store->address, store->SDDport, - tls_need); + tls_need); if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { return false; } @@ -244,7 +244,7 @@ bool do_backup(JCR *jcr) if (stat == JS_Terminated) { backup_cleanup(jcr, stat); return true; - } + } return false; } @@ -267,21 +267,21 @@ int wait_for_job_termination(JCR *jcr) /* Wait for Client to terminate */ while ((n = bget_dirmsg(fd)) >= 0) { if (!fd_ok && sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles, - &ReadBytes, &JobBytes, &Errors) == 5) { - fd_ok = true; - set_jcr_job_status(jcr, jcr->FDJobStatus); + &ReadBytes, &JobBytes, &Errors) == 5) { + fd_ok = true; + set_jcr_job_status(jcr, jcr->FDJobStatus); Dmsg1(100, "FDStatus=%c\n", (char)jcr->JobStatus); } else { Jmsg(jcr, M_WARNING, 0, _("Unexpected Client Job message: %s\n"), - fd->msg); + fd->msg); } if (job_canceled(jcr)) { - break; + break; } } if (is_bnet_error(fd)) { Jmsg(jcr, M_FATAL, 0, _("Network error with FD during %s: ERR=%s\n"), - job_type_to_str(jcr->JobType), bnet_strerror(fd)); + job_type_to_str(jcr->JobType), bnet_strerror(fd)); } bnet_sig(fd, BNET_TERMINATE); /* tell Client we are terminating */ @@ -320,7 +320,7 @@ int wait_for_job_termination(JCR *jcr) */ void backup_cleanup(JCR *jcr, int TermCode) { - char sdt[50], edt[50]; + char sdt[50], edt[50], schedt[50]; char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50]; char term_code[100], fd_term_msg[100], sd_term_msg[100]; const char *term_msg; @@ -330,22 +330,22 @@ void backup_cleanup(JCR *jcr, int TermCode) utime_t RunTime; Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode); - dequeue_messages(jcr); /* display any queued messages */ + dequeue_messages(jcr); /* display any queued messages */ memset(&mr, 0, sizeof(mr)); set_jcr_job_status(jcr, TermCode); - update_job_end_record(jcr); /* update database */ + update_job_end_record(jcr); /* update database */ if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting job record for stats: %s"), - db_strerror(jcr->db)); + db_strerror(jcr->db)); set_jcr_job_status(jcr, JS_ErrorTerminated); } bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName)); if (!db_get_media_record(jcr, jcr->db, &mr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"), - mr.VolumeName, db_strerror(jcr->db)); + mr.VolumeName, db_strerror(jcr->db)); set_jcr_job_status(jcr, JS_ErrorTerminated); } @@ -360,88 +360,89 @@ void backup_cleanup(JCR *jcr, int TermCode) int VolCount; if (*fname == '|') { - fname++; - got_pipe = 1; + fname++; + got_pipe = 1; bpipe = open_bpipe(fname, 0, "w"); - fd = bpipe ? bpipe->wfd : NULL; + fd = bpipe ? bpipe->wfd : NULL; } else { - /* ***FIXME*** handle BASE */ + /* ***FIXME*** handle BASE */ fd = fopen(fname, jcr->JobLevel==L_FULL?"w+":"a+"); } if (fd) { - VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId, - &VolParams); - if (VolCount == 0) { + VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId, + &VolParams); + if (VolCount == 0) { Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters to " "update Bootstrap file. ERR=%s\n"), db_strerror(jcr->db)); - if (jcr->SDJobFiles != 0) { - set_jcr_job_status(jcr, JS_ErrorTerminated); - } + if (jcr->SDJobFiles != 0) { + set_jcr_job_status(jcr, JS_ErrorTerminated); + } - } - for (int i=0; i < VolCount; i++) { - /* Write the record */ + } + for (int i=0; i < VolCount; i++) { + /* Write the record */ fprintf(fd, "Volume=\"%s\"\n", VolParams[i].VolumeName); fprintf(fd, "MediaType=\"%s\"\n", VolParams[i].MediaType); fprintf(fd, "VolSessionId=%u\n", jcr->VolSessionId); fprintf(fd, "VolSessionTime=%u\n", jcr->VolSessionTime); fprintf(fd, "VolFile=%u-%u\n", VolParams[i].StartFile, - VolParams[i].EndFile); + VolParams[i].EndFile); fprintf(fd, "VolBlock=%u-%u\n", VolParams[i].StartBlock, - VolParams[i].EndBlock); + VolParams[i].EndBlock); fprintf(fd, "FileIndex=%d-%d\n", VolParams[i].FirstIndex, - VolParams[i].LastIndex); - } - if (VolParams) { - free(VolParams); - } - if (got_pipe) { - close_bpipe(bpipe); - } else { - fclose(fd); - } + VolParams[i].LastIndex); + } + if (VolParams) { + free(VolParams); + } + if (got_pipe) { + close_bpipe(bpipe); + } else { + fclose(fd); + } } else { - berrno be; + berrno be; Jmsg(jcr, M_ERROR, 0, _("Could not open WriteBootstrap file:\n" "%s: ERR=%s\n"), fname, be.strerror()); - set_jcr_job_status(jcr, JS_ErrorTerminated); + set_jcr_job_status(jcr, JS_ErrorTerminated); } } - msg_type = M_INFO; /* by default INFO message */ + msg_type = M_INFO; /* by default INFO message */ switch (jcr->JobStatus) { case JS_Terminated: - if (jcr->Errors || jcr->SDErrors) { + if (jcr->Errors || jcr->SDErrors) { term_msg = _("Backup OK -- with warnings"); - } else { + } else { term_msg = _("Backup OK"); - } - break; + } + break; case JS_FatalError: case JS_ErrorTerminated: term_msg = _("*** Backup Error ***"); - msg_type = M_ERROR; /* Generate error message */ - if (jcr->store_bsock) { - bnet_sig(jcr->store_bsock, BNET_TERMINATE); - if (jcr->SD_msg_chan) { - pthread_cancel(jcr->SD_msg_chan); - } - } - break; + msg_type = M_ERROR; /* Generate error message */ + if (jcr->store_bsock) { + bnet_sig(jcr->store_bsock, BNET_TERMINATE); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } + } + break; case JS_Canceled: term_msg = _("Backup Canceled"); - if (jcr->store_bsock) { - bnet_sig(jcr->store_bsock, BNET_TERMINATE); - if (jcr->SD_msg_chan) { - pthread_cancel(jcr->SD_msg_chan); - } - } - break; + if (jcr->store_bsock) { + bnet_sig(jcr->store_bsock, BNET_TERMINATE); + if (jcr->SD_msg_chan) { + pthread_cancel(jcr->SD_msg_chan); + } + } + break; default: - term_msg = term_code; + term_msg = term_code; sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus); - break; + break; } + bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime); bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime); bstrftimes(edt, sizeof(edt), jcr->jr.EndTime); RunTime = jcr->jr.EndTime - jcr->jr.StartTime; @@ -460,7 +461,7 @@ void backup_cleanup(JCR *jcr, int TermCode) if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); } - jcr->VolumeName[0] = 0; /* none */ + jcr->VolumeName[0] = 0; /* none */ } if (jcr->ReadBytes == 0) { @@ -476,7 +477,7 @@ void backup_cleanup(JCR *jcr, int TermCode) jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg)); -// bmicrosleep(15, 0); /* for debugging SIGHUP */ +// bmicrosleep(15, 0); /* for debugging SIGHUP */ Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n" " JobId: %d\n" @@ -486,8 +487,10 @@ void backup_cleanup(JCR *jcr, int TermCode) " FileSet: \"%s\" %s\n" " Pool: \"%s\"\n" " Storage: \"%s\"\n" +" Scheduled time: %s\n" " Start time: %s\n" " End time: %s\n" +" Priority: %d\n" " FD Files Written: %s\n" " SD Files Written: %s\n" " FD Bytes Written: %s\n" @@ -503,31 +506,33 @@ void backup_cleanup(JCR *jcr, int TermCode) " FD termination status: %s\n" " SD termination status: %s\n" " Termination: %s\n\n"), - edt, - jcr->jr.JobId, - jcr->jr.Job, - level_to_str(jcr->JobLevel), jcr->since, - jcr->client->hdr.name, - jcr->fileset->hdr.name, jcr->FSCreateTime, - jcr->pool->hdr.name, - jcr->store->hdr.name, - sdt, - edt, - edit_uint64_with_commas(jcr->jr.JobFiles, ec1), - edit_uint64_with_commas(jcr->SDJobFiles, ec4), - edit_uint64_with_commas(jcr->jr.JobBytes, ec2), - edit_uint64_with_commas(jcr->SDJobBytes, ec5), - (float)kbps, - compress, - jcr->VolumeName, - jcr->VolSessionId, - jcr->VolSessionTime, - edit_uint64_with_commas(mr.VolBytes, ec3), - jcr->Errors, - jcr->SDErrors, - fd_term_msg, - sd_term_msg, - term_msg); + edt, + jcr->jr.JobId, + jcr->jr.Job, + level_to_str(jcr->JobLevel), jcr->since, + jcr->client->hdr.name, + jcr->fileset->hdr.name, jcr->FSCreateTime, + jcr->pool->hdr.name, + jcr->store->hdr.name, + schedt, + sdt, + edt, + jcr->JobPriority, + edit_uint64_with_commas(jcr->jr.JobFiles, ec1), + edit_uint64_with_commas(jcr->SDJobFiles, ec4), + edit_uint64_with_commas(jcr->jr.JobBytes, ec2), + edit_uint64_with_commas(jcr->SDJobBytes, ec5), + (float)kbps, + compress, + jcr->VolumeName, + jcr->VolSessionId, + jcr->VolSessionTime, + edit_uint64_with_commas(mr.VolBytes, ec3), + jcr->Errors, + jcr->SDErrors, + fd_term_msg, + sd_term_msg, + term_msg); Dmsg0(100, "Leave backup_cleanup()\n"); } diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index f8bad7653e..5f5de77d8d 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -151,7 +151,6 @@ JobId_t run_job(JCR *jcr) return JobId; bail_out: - generate_daemon_event(jcr, "JobEnd"); if (jcr->fname) { free_memory(jcr->fname); jcr->fname = NULL; @@ -178,7 +177,21 @@ static void *job_thread(void *arg) Dmsg0(200, "=====Start Job=========\n"); jcr->start_time = time(NULL); /* set the real start time */ jcr->jr.StartTime = jcr->start_time; - set_jcr_job_status(jcr, JS_Running); + + if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay < + (utime_t)(jcr->start_time - jcr->sched_time)) { + Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n")); + set_jcr_job_status(jcr, JS_Canceled); + } + + /* + * Note, we continue, even if the job is canceled above. This + * will permit proper setting of the job start record and + * the error (cancel) will be picked up below. + */ + + generate_job_event(jcr, "JobInit"); + set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */ if (!jcr->fname) { jcr->fname = get_pool_memory(PM_FNAME); @@ -230,12 +243,6 @@ static void *job_thread(void *arg) if (job_canceled(jcr)) { update_job_end_record(jcr); - } else if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay < - (utime_t)(jcr->start_time - jcr->sched_time)) { - Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n")); - set_jcr_job_status(jcr, JS_Canceled); - update_job_end_record(jcr); - } else { /* Run Job */ @@ -260,6 +267,9 @@ static void *job_thread(void *arg) goto bail_out; } } + + generate_job_event(jcr, "JobRun"); + switch (jcr->JobType) { case JT_BACKUP: if (do_backup(jcr)) { @@ -338,6 +348,7 @@ static void *job_thread(void *arg) dequeue_messages(jcr); } } + bail_out: generate_daemon_event(jcr, "JobEnd"); Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus); @@ -357,6 +368,8 @@ int cancel_job(UAContext *ua, JCR *jcr) { BSOCK *sd, *fd; + set_jcr_job_status(jcr, JS_Canceled); + switch (jcr->JobStatus) { case JS_Created: case JS_WaitJobRes: @@ -365,14 +378,12 @@ int cancel_job(UAContext *ua, JCR *jcr) case JS_WaitPriority: case JS_WaitMaxJobs: case JS_WaitStartTime: - set_jcr_job_status(jcr, JS_Canceled); bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"), jcr->JobId, jcr->Job); jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */ return 1; default: - set_jcr_job_status(jcr, JS_Canceled); /* Cancel File daemon */ if (jcr->file_bsock) { diff --git a/bacula/src/dird/pythondir.c b/bacula/src/dird/pythondir.c index 4ab14fb785..a3452fd115 100644 --- a/bacula/src/dird/pythondir.c +++ b/bacula/src/dird/pythondir.c @@ -40,22 +40,16 @@ extern PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name); -static int set_job_events(PyObject *self, PyObject *arg); -static int job_run(PyObject *self, PyObject *arg); +static PyObject *set_job_events(PyObject *self, PyObject *arg); +static PyObject *job_run(PyObject *self, PyObject *arg); +static PyObject *job_write(PyObject *self, PyObject *arg); -#ifdef needed -static PyObject *set_bacula_job_events(PyObject *self, PyObject *arg) -{ - Dmsg2(000, "In set_bacula_job_events self=%p arg=%p\n", - self, arg); - Py_INCREF(Py_None); - return Py_None; -} PyMethodDef JobMethods[] = { - {"set_events", set_bacula_job_events, METH_VARARGS, "Define Bacula events."}, + {"set_events", set_job_events, METH_VARARGS, "Set Job events"}, + {"run", job_run, METH_VARARGS, "Run a Job"}, + {"write", job_write, METH_VARARGS, "Write to output"}, {NULL, NULL, 0, NULL} /* last item */ }; -#endif struct s_vars { @@ -78,17 +72,16 @@ static struct s_vars getvars[] = { { N_("MediaType"), "s"}, { N_("JobName"), "s"}, { N_("JobStatus"), "s"}, + { N_("Priority"), "i"}, { NULL, NULL} }; /* Writable variables */ static struct s_vars setvars[] = { - { N_("set_events"), NULL}, - { N_("run"), NULL}, { N_("JobReport"), "s"}, - { N_("write"), "s"}, - { N_("VolumeName") , "s"}, + { N_("VolumeName"), "s"}, + { N_("Priority"), "i"}, { NULL, NULL} }; @@ -119,7 +112,8 @@ PyObject *job_getattr(PyObject *self, char *attrname) } } if (!found) { - goto not_found; + /* Try our methods */ + return Py_FindMethod(JobMethods, self, attrname); } switch (i) { case 0: /* Job */ @@ -150,8 +144,9 @@ PyObject *job_getattr(PyObject *self, char *attrname) buf[1] = 0; buf[0] = jcr->JobStatus; return Py_BuildValue(getvars[i].fmt, buf); + case 13: /* Priority */ + return Py_BuildValue(getvars[i].fmt, jcr->JobPriority); } -not_found: bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname); bail_out: PyErr_SetString(PyExc_AttributeError, errmsg); @@ -168,6 +163,7 @@ int job_setattr(PyObject *self, char *attrname, PyObject *value) JCR *jcr; bool found = false; char *strval = NULL; + int intval = 0; int i; Dmsg2(100, "In job_setattr=%s val=%p.\n", attrname, value); @@ -189,23 +185,28 @@ int job_setattr(PyObject *self, char *attrname, PyObject *value) if (!found) { goto bail_out; } - /* Get argument value ***FIXME*** handle other formats */ + /* Get argument value */ if (setvars[i].fmt != NULL) { - if (!PyArg_Parse(value, setvars[i].fmt, &strval)) { - PyErr_SetString(PyExc_TypeError, "Read-only attribute"); - return -1; + switch (setvars[i].fmt[0]) { + case 's': + if (!PyArg_Parse(value, setvars[i].fmt, &strval)) { + PyErr_SetString(PyExc_TypeError, "Read-only attribute"); + return -1; + } + break; + case 'i': + if (!PyArg_Parse(value, setvars[i].fmt, &intval)) { + PyErr_SetString(PyExc_TypeError, "Read-only attribute"); + return -1; + } + break; } } switch (i) { - case 0: /* set_events */ - return set_job_events(self, value); - case 1: /* run */ - return job_run(self, value); - case 2: /* JobReport */ - case 3: /* write */ + case 0: /* JobReport */ Jmsg(jcr, M_INFO, 0, "%s", strval); return 0; - case 4: /* VolumeName */ + case 1: /* VolumeName */ /* Make sure VolumeName is valid and we are in VolumeName event */ if (strcmp("NewVolume", jcr->event) == 0 && is_volume_name_legal(NULL, strval)) { @@ -215,49 +216,48 @@ int job_setattr(PyObject *self, char *attrname, PyObject *value) } else { jcr->VolumeName[0] = 0; } + break; + case 2: /* Priority */ + Dmsg1(000, "Set priority=%d\n", intval); + return 0; } bail_out: PyErr_SetString(PyExc_AttributeError, attrname); return -1; } -#ifdef needed -static PyObject *set_bacula_job_events(PyObject *self, PyObject *arg) -{ - Dmsg2(000, "In set_bacula_job_events self=%p arg=%p\n", - self, arg); - Py_INCREF(Py_None); - return Py_None; -} -#endif - -static int set_job_events(PyObject *self, PyObject *arg) +static PyObject *set_job_events(PyObject *self, PyObject *arg) { PyObject *eObject; JCR *jcr; Dmsg0(100, "In set_job_events.\n"); - if (!PyArg_Parse(arg, "O", &eObject)) { - return -1; + if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) { + Dmsg0(000, "Error in ParseTuple\n"); + return NULL; } jcr = get_jcr_from_PyObject(self); Py_XDECREF((PyObject *)jcr->Python_events); Py_INCREF(eObject); jcr->Python_events = (void *)eObject; - return 0; /* good return */ + Py_INCREF(Py_None); + return Py_None; } /* Run a Bacula command */ -static int job_run(PyObject *self, PyObject *arg) +static PyObject *job_run(PyObject *self, PyObject *arg) { JCR *jcr; char *item; int stat; - if (!PyArg_Parse(arg, "s", &item)) { - return -1; + if (!PyArg_ParseTuple(arg, "s:run", &item)) { + Dmsg0(000, "Error in ParseTuple\n"); + return NULL; } + /* Release lock due to recursion */ + PyEval_ReleaseLock(); jcr = get_jcr_from_PyObject(self); UAContext *ua = new_ua_context(jcr); ua->batch = true; @@ -265,25 +265,45 @@ static int job_run(PyObject *self, PyObject *arg) parse_ua_args(ua); /* parse command */ stat = run_cmd(ua, ua->cmd); free_ua_context(ua); - /* ***FIXME*** check stat */ - return 0; + PyEval_AcquireLock(); + return PyInt_FromLong((long)stat); +} + +static PyObject *job_write(PyObject *self, PyObject *args) +{ + char *text = NULL; + + if (!PyArg_ParseTuple(args, "s:write", &text)) { + Dmsg0(000, "Parse tuple error in job_write\n"); + return NULL; + } + if (text) { + Jmsg(NULL, M_INFO, 0, "%s", text); + } + Py_INCREF(Py_None); + return Py_None; } +/* + * Generate a Job event, which means look up the event + * method defined by the user, and if it exists, + * call it. + */ int generate_job_event(JCR *jcr, const char *event) { PyObject *method = NULL; PyObject *Job = (PyObject *)jcr->Python_job; + PyObject *events = (PyObject *)jcr->Python_events; PyObject *result = NULL; int stat = 0; - if (!Job) { + if (!Job || !events) { return 0; } PyEval_AcquireLock(); - PyObject *events = (PyObject *)jcr->Python_events; method = find_method(events, method, event); if (!method) { goto bail_out; diff --git a/bacula/src/filed/pythonfd.c b/bacula/src/filed/pythonfd.c index acb70906bd..bf2646973d 100644 --- a/bacula/src/filed/pythonfd.c +++ b/bacula/src/filed/pythonfd.c @@ -47,7 +47,15 @@ extern PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name); /* Forward referenced functions */ -static int set_job_events(PyObject *self, PyObject *arg); +static PyObject *set_job_events(PyObject *self, PyObject *arg); +static PyObject *job_write(PyObject *self, PyObject *arg); + +PyMethodDef JobMethods[] = { + {"set_events", set_job_events, METH_VARARGS, "Set Job events"}, + {"write", job_write, METH_VARARGS, "Write to output"}, + {NULL, NULL, 0, NULL} /* last item */ +}; + bool my_python_set_prog(JCR *jcr, const char *prog); int my_python_open(BFILE *bfd, const char *fname, int flags, mode_t mode); @@ -75,9 +83,7 @@ static struct s_vars getvars[] = { /* Writable variables */ static struct s_vars setvars[] = { - { N_("set_events"), NULL}, { N_("JobReport"), "s"}, - { N_("write"), "s"}, { NULL, NULL} }; @@ -103,7 +109,8 @@ PyObject *job_getattr(PyObject *self, char *attrname) } } if (!found) { - goto not_found; + /* Try our methods */ + return Py_FindMethod(JobMethods, self, attrname); } switch (i) { case 0: /* FD's name */ @@ -123,7 +130,6 @@ PyObject *job_getattr(PyObject *self, char *attrname) buf[0] = jcr->JobStatus; return Py_BuildValue(getvars[i].fmt, buf); } -not_found: bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname); bail_out: PyErr_SetString(PyExc_AttributeError, errmsg); @@ -171,10 +177,7 @@ int job_setattr(PyObject *self, char *attrname, PyObject *value) } } switch (i) { - case 0: /* set_events */ - return set_job_events(self, value); - case 1: /* JobReport */ - case 2: /* write */ + case 0: /* JobReport */ Jmsg(jcr, M_INFO, 0, "%s", strval); return 0; } @@ -186,21 +189,36 @@ bail_out: } +static PyObject *job_write(PyObject *self, PyObject *args) +{ + char *text = NULL; + + if (!PyArg_ParseTuple(args, "s:write", &text)) { + Dmsg0(000, "Parse tuple error in job_write\n"); + return NULL; + } + if (text) { + Jmsg(NULL, M_INFO, 0, "%s", text); + } + Py_INCREF(Py_None); + return Py_None; +} + -static int set_job_events(PyObject *self, PyObject *arg) +static PyObject *set_job_events(PyObject *self, PyObject *arg) { PyObject *eObject; JCR *jcr; Dmsg0(100, "In set_job_events.\n"); - if (!PyArg_Parse(arg, "O", &eObject)) { + if (!PyArg_ParseTuple(arg, "O", &eObject)) { Dmsg0(000, "Parse error looking for Object argument\n"); - return -1; + return NULL; } jcr = get_jcr_from_PyObject(self); if (!jcr) { PyErr_SetString(PyExc_AttributeError, "Job pointer not found."); - return -1; + return NULL; } Py_XDECREF((PyObject *)jcr->Python_events); /* release any old events Object */ Py_INCREF(eObject); @@ -212,7 +230,8 @@ static int set_job_events(PyObject *self, PyObject *arg) python_close = my_python_close; python_read = my_python_read; - return 0; + Py_INCREF(Py_None); + return Py_None; } @@ -220,16 +239,16 @@ int generate_job_event(JCR *jcr, const char *event) { PyObject *method = NULL; PyObject *Job = (PyObject *)jcr->Python_job; + PyObject *events = (PyObject *)jcr->Python_events; PyObject *result = NULL; int stat = 0; - if (!Job) { + if (!Job || !events) { return 0; } PyEval_AcquireLock(); - PyObject *events = (PyObject *)jcr->Python_events; method = find_method(events, method, event); if (!method) { goto bail_out; diff --git a/bacula/src/lib/pythonlib.c b/bacula/src/lib/pythonlib.c index 5af7ff6a0a..cbfe67bd42 100644 --- a/bacula/src/lib/pythonlib.c +++ b/bacula/src/lib/pythonlib.c @@ -250,8 +250,7 @@ int generate_daemon_event(JCR *jcr, const char *event) } else if (strcmp(event, "JobEnd") == 0) { if (!JobEnd_method || !jcr->Python_job) { - Dmsg2(000, "No JobEnd method=%p Job=%p\n", JobEnd_method, jcr->Python_job); - stat = 0; + stat = 0; /* probably already here */ goto bail_out; } bstrncpy(jcr->event, event, sizeof(jcr->event)); diff --git a/bacula/src/stored/fd_cmds.c b/bacula/src/stored/fd_cmds.c index 71a75615cd..330ee30b9a 100644 --- a/bacula/src/stored/fd_cmds.c +++ b/bacula/src/stored/fd_cmds.c @@ -74,7 +74,7 @@ static struct s_cmds fd_cmds[] = { {"read data", read_data_cmd}, {"read close", read_close_session}, {"bootstrap", bootstrap_cmd}, - {NULL, NULL} /* list terminator */ + {NULL, NULL} /* list terminator */ }; /* Commands from the File daemon that require additional scanning */ @@ -93,7 +93,7 @@ static char ERROR_bootstrap[] = "3904 Error bootstrap\n"; /* Information sent to the Director */ static char Job_start[] = "3010 Job %s start\n"; -static char Job_end[] = +static char Job_end[] = "3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n"; /* @@ -120,43 +120,44 @@ void run_job(JCR *jcr) jcr->start_time = time(NULL); jcr->run_time = jcr->start_time; set_jcr_job_status(jcr, JS_Running); - dir_send_job_status(jcr); /* update director */ + dir_send_job_status(jcr); /* update director */ for (quit=false; !quit;) { int stat; /* Read command coming from the File daemon */ stat = bnet_recv(fd); - if (is_bnet_stop(fd)) { /* hardeof or error */ - break; /* connection terminated */ + if (is_bnet_stop(fd)) { /* hardeof or error */ + break; /* connection terminated */ } if (stat <= 0) { - continue; /* ignore signals and zero length msgs */ + continue; /* ignore signals and zero length msgs */ } Dmsg1(110, "msg); found = false; for (i=0; fd_cmds[i].cmd; i++) { - if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) { - found = true; /* indicate command found */ - if (!fd_cmds[i].func(jcr)) { /* do command */ - set_jcr_job_status(jcr, JS_ErrorTerminated); - quit = true; - } - break; - } + if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) { + found = true; /* indicate command found */ + if (!fd_cmds[i].func(jcr)) { /* do command */ + set_jcr_job_status(jcr, JS_ErrorTerminated); + quit = true; + } + break; + } } - if (!found) { /* command not found */ + if (!found) { /* command not found */ Dmsg1(110, "msg); - bnet_fsend(fd, ferrmsg); - break; + bnet_fsend(fd, ferrmsg); + break; } } bnet_sig(fd, BNET_TERMINATE); /* signal to FD job is done */ jcr->end_time = time(NULL); - dequeue_messages(jcr); /* send any queued messages */ + dequeue_messages(jcr); /* send any queued messages */ set_jcr_job_status(jcr, JS_Terminated); + generate_daemon_event(jcr, "JobEnd"); bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, edit_uint64(jcr->JobBytes, ec1)); - bnet_sig(dir, BNET_EOD); /* send EOD to Director daemon */ + bnet_sig(dir, BNET_EOD); /* send EOD to Director daemon */ return; } @@ -175,10 +176,10 @@ static bool append_data_cmd(JCR *jcr) Dmsg1(110, "msg); jcr->JobType = JT_BACKUP; if (do_append_data(jcr)) { - return bnet_fsend(fd, OK_append); + return bnet_fsend(fd, OK_append); } else { - bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */ - bnet_fsend(fd, ERROR_append); + bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */ + bnet_fsend(fd, ERROR_append); } } else { bnet_fsend(fd, NOT_opened); @@ -225,8 +226,8 @@ static bool append_open_session(JCR *jcr) /* * Append Close session command - * Close the append session and send back Statistics - * (need to fix statistics) + * Close the append session and send back Statistics + * (need to fix statistics) */ static bool append_close_session(JCR *jcr) { @@ -241,7 +242,7 @@ static bool append_close_session(JCR *jcr) bnet_fsend(fd, OK_close, jcr->JobStatus); Dmsg1(120, ">filed: %s", fd->msg); - bnet_sig(fd, BNET_EOD); /* send EOD to File daemon */ + bnet_sig(fd, BNET_EOD); /* send EOD to File daemon */ jcr->session_opened = false; return true; @@ -284,18 +285,18 @@ static bool read_open_session(JCR *jcr) } if (sscanf(fd->msg, read_open, jcr->dcr->VolumeName, &jcr->read_VolSessionId, - &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile, - &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) { + &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile, + &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) { if (jcr->session_opened) { - bnet_fsend(fd, NOT_opened); - return false; + bnet_fsend(fd, NOT_opened); + return false; } Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n", - jcr->JobId, jcr->dcr->VolumeName, jcr->read_VolSessionId, - jcr->read_VolSessionTime); + jcr->JobId, jcr->dcr->VolumeName, jcr->read_VolSessionId, + jcr->read_VolSessionTime); Dmsg4(100, " StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n", - jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock, - jcr->read_EndBlock); + jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock, + jcr->read_EndBlock); } jcr->session_opened = true; @@ -326,7 +327,7 @@ bool bootstrap_cmd(JCR *jcr) bs = fopen(fname, "a+"); /* create file */ if (!bs) { Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"), - jcr->RestoreBootstrap, strerror(errno)); + jcr->RestoreBootstrap, strerror(errno)); goto bail_out; } while (bnet_recv(fd) >= 0) { @@ -358,7 +359,7 @@ bail_out: /* * Read Close session command - * Close the read session + * Close the read session */ static bool read_close_session(JCR *jcr) { @@ -373,7 +374,7 @@ static bool read_close_session(JCR *jcr) bnet_fsend(fd, OK_close); Dmsg1(160, ">filed: %s\n", fd->msg); - bnet_sig(fd, BNET_EOD); /* send EOD to File daemon */ + bnet_sig(fd, BNET_EOD); /* send EOD to File daemon */ jcr->session_opened = false; return true; diff --git a/bacula/src/stored/pythonsd.c b/bacula/src/stored/pythonsd.c index 85ca46ed2e..40b21880e6 100644 --- a/bacula/src/stored/pythonsd.c +++ b/bacula/src/stored/pythonsd.c @@ -39,7 +39,14 @@ extern JCR *get_jcr_from_PyObject(PyObject *self); extern PyObject *find_method(PyObject *eventsObject, PyObject *method, const char *name); -static int set_job_events(PyObject *self, PyObject *arg); +static PyObject *set_job_events(PyObject *self, PyObject *arg); +static PyObject *job_write(PyObject *self, PyObject *arg); + +PyMethodDef JobMethods[] = { + {"set_events", set_job_events, METH_VARARGS, "Set Job events"}, + {"write", job_write, METH_VARARGS, "Write to output"}, + {NULL, NULL, 0, NULL} /* last item */ +}; struct s_vars { @@ -67,9 +74,7 @@ static struct s_vars getvars[] = { /* Writable variables */ static struct s_vars setvars[] = { - { N_("set_events"), NULL}, { N_("JobReport"), "s"}, - { N_("write"), "s"}, { NULL, NULL} }; @@ -98,7 +103,8 @@ PyObject *job_getattr(PyObject *self, char *attrname) } } if (!found) { - goto not_found; + /* Try our methods */ + return Py_FindMethod(JobMethods, self, attrname); } switch (i) { case 0: /* Job */ @@ -128,7 +134,6 @@ PyObject *job_getattr(PyObject *self, char *attrname) case 11: return Py_BuildValue(getvars[i].fmt, jcr->dcr->dev_name); } -not_found: bsnprintf(errmsg, sizeof(errmsg), "Attribute %s not found.", attrname); bail_out: PyErr_SetString(PyExc_AttributeError, errmsg); @@ -174,10 +179,7 @@ int job_setattr(PyObject *self, char *attrname, PyObject *value) } } switch (i) { - case 0: /* set_events */ - return set_job_events(self, value); - case 1: /* JobReport */ - case 2: /* write */ + case 0: /* JobReport */ Jmsg(jcr, M_INFO, 0, "%s", strval); return 0; } @@ -190,26 +192,37 @@ bail_out: } -static int set_job_events(PyObject *self, PyObject *arg) +static PyObject *set_job_events(PyObject *self, PyObject *arg) { PyObject *eObject; JCR *jcr; Dmsg0(100, "In set_job_events.\n"); - if (!PyArg_Parse(arg, "O", &eObject)) { - Dmsg0(000, "Parse error looking for Object argument\n"); - return -1; + if (!PyArg_ParseTuple(arg, "O:set_events", &eObject)) { + Dmsg0(000, "Error in ParseTuple\n"); + return NULL; } jcr = get_jcr_from_PyObject(self); - if (!jcr) { - PyErr_SetString(PyExc_AttributeError, "Job pointer not found."); - return -1; - } - Py_XDECREF((PyObject *)jcr->Python_events); /* release any old events Object */ + Py_XDECREF((PyObject *)jcr->Python_events); Py_INCREF(eObject); - jcr->Python_events = (void *)eObject; /* set new events */ + jcr->Python_events = (void *)eObject; + Py_INCREF(Py_None); + return Py_None; +} - return 0; +static PyObject *job_write(PyObject *self, PyObject *args) +{ + char *text = NULL; + + if (!PyArg_ParseTuple(args, "s:write", &text)) { + Dmsg0(000, "Parse tuple error in job_write\n"); + return NULL; + } + if (text) { + Jmsg(NULL, M_INFO, 0, "%s", text); + } + Py_INCREF(Py_None); + return Py_None; } @@ -217,16 +230,16 @@ int generate_job_event(JCR *jcr, const char *event) { PyObject *method = NULL; PyObject *Job = (PyObject *)jcr->Python_job; + PyObject *events = (PyObject *)jcr->Python_events; PyObject *result = NULL; int stat = 0; - if (!Job) { + if (!Job || !events) { return 0; } PyEval_AcquireLock(); - PyObject *events = (PyObject *)jcr->Python_events; method = find_method(events, method, event); if (!method) { goto bail_out; diff --git a/bacula/src/tools/bsmtp.c b/bacula/src/tools/bsmtp.c index f9135266a7..3fddb610cb 100644 --- a/bacula/src/tools/bsmtp.c +++ b/bacula/src/tools/bsmtp.c @@ -125,7 +125,7 @@ static void usage() { fprintf(stderr, "\n" -"Usage: %s [-f from] [-h mailhost] [-s subject] [-c copy] [recepient ...]\n" +"Usage: %s [-f from] [-h mailhost] [-s subject] [-c copy] [recipient ...]\n" " -c set the Cc: field\n" " -dnn set debug level to nn\n" " -f set the From: field\n" diff --git a/bacula/src/version.h b/bacula/src/version.h index c8b4c9d4c8..7b9538329c 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -12,7 +12,7 @@ #define TRACE_FILE 1 /* If this is set stdout will not be closed on startup */ -/* #define DEVELOPER 1 */ +#define DEVELOPER 1