On Sat, Mar 14, 2009 at 09:14:18PM +0100, Kern Sibbald wrote:
> On Friday 13 March 2009 12:38:14 Graham Keeling wrote:
> > Under the current design:
> >
> > The director connects to the storage daemon, and gets an
> > sd_auth_key. The director then connects to the file daemon, and gives it
> > the sd_auth_key with the 'jobcmd'.
> > (restoring of files happens)
> > The director does a 'wait_for_storage_daemon_termination()'.
> > The director waits for the file daemon to indicate the end of the
> > job.
> >
> > With my idea:
> >
> > The director connects to the file daemon.
> > Then, for each storage daemon in the .bsr file... {
> > The director connects to the storage daemon, and gets an
> > sd_auth_key. The director then connects to the file daemon, and gives it
> > the sd_auth_key with the 'storaddr' command.
> > (restoring of files happens)
> > The director does a 'wait_for_storage_daemon_termination()'.
> > The director waits for the file daemon to indicate the end of the
> > work on this storage.
> > }
> > The director tells the file daemon that there are no more storages to
> > contact. The director waits for the file daemon to indicate the end of the
> > job.
> >
> > As you can see, each restore between the file daemon and storage daemon is
> > handled in the same way that it is currently handled, using the same method
> > for authentication, except that the sd_auth_key is moved from the 'jobcmd'
> > to the 'storaddr' command - where it logically belongs.
>
> I've added your request along with this clarification of the implementation
> details to the projects list.
Thank you.
Attached are my patches, which apply to SVN as of the 18th of March 2009.
The first patch file provides the functionality. Using old file daemons with
the patched director code works fine for me.
Currently, the message at the end of the job doesn't print a list of
SDJobStatuses - it will print the last one that it got. I think this is
fine, because if they all complete OK, it will print 'OK'. If one of them
was not OK, the job would end before going onto the next storage, and you'll
be given that last status.
The second patch file tidies up large chunks of repeated code in
src/dird/bsr.c into functions, which would be nice to have, regardless of the
first patch.
Graham.
Index: WORK/src/dird/backup.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/dird/backup.c,v
retrieving revision 1.1
diff -u -r1.1 backup.c
--- WORK/src/dird/backup.c 5 Jan 2009 16:06:53 -0000 1.1
+++ WORK/src/dird/backup.c 18 Mar 2009 17:17:55 -0000
@@ -47,7 +47,7 @@
/* Commands sent to File daemon */
static char backupcmd[] = "backup\n";
-static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
+static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%s\n";
/* Responses received from File daemon */
static char OKbackup[] = "2000 OK backup\n";
@@ -278,7 +278,8 @@
}
}
- fd->fsend(storaddr, store->address, store->SDDport, tls_need);
+ fd->fsend(storaddr, store->address, store->SDDport, tls_need,
+ jcr->sd_auth_key);
if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
goto bail_out;
}
@@ -343,7 +344,7 @@
* are done, we return the job status.
* Also used by restore.c
*/
-int wait_for_job_termination(JCR *jcr, int timeout)
+static int wait_for_job_termination_do(JCR *jcr, int timeout, int storage_too)
{
int32_t n = 0;
BSOCK *fd = jcr->file_bsock;
@@ -396,7 +397,7 @@
}
/* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
- wait_for_storage_daemon_termination(jcr);
+ if(storage_too) wait_for_storage_daemon_termination(jcr);
/* Return values from FD */
if (fd_ok) {
@@ -423,7 +424,18 @@
if (jcr->FDJobStatus != JS_Terminated) {
return jcr->FDJobStatus;
}
- return jcr->SDJobStatus;
+ if(storage_too) return jcr->SDJobStatus;
+ else return jcr->FDJobStatus;
+}
+
+int wait_for_job_termination(JCR *jcr, int timeout)
+{
+ return wait_for_job_termination_do(jcr, timeout, 1);
+}
+
+int wait_for_job_termination_fd(JCR *jcr, int timeout)
+{
+ return wait_for_job_termination_do(jcr, timeout, 0);
}
/*
Index: WORK/src/dird/bsr.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/dird/bsr.c,v
retrieving revision 1.1
diff -u -r1.1 bsr.c
--- WORK/src/dird/bsr.c 5 Jan 2009 16:06:53 -0000 1.1
+++ WORK/src/dird/bsr.c 18 Mar 2009 17:17:55 -0000
@@ -350,6 +350,7 @@
find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
bsr->VolParams[i].MediaType);
}
+ fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
if (bsr->fileregex) {
@@ -406,6 +407,7 @@
find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
bsr->VolParams[i].MediaType);
}
+ fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
if (bsr->fileregex) {
Index: WORK/src/dird/fd_cmds.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/dird/fd_cmds.c,v
retrieving revision 1.1
diff -u -r1.1 fd_cmds.c
--- WORK/src/dird/fd_cmds.c 5 Jan 2009 16:06:53 -0000 1.1
+++ WORK/src/dird/fd_cmds.c 18 Mar 2009 17:17:55 -0000
@@ -48,7 +48,8 @@
/* Commands sent to File daemon */
static char filesetcmd[] = "fileset%s\n"; /* set full fileset */
-static char jobcmd[] = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
+static char jobcmd[] = "JobId=%s Job=%s SDid=%u SDtime=%u\n";
+static char jobcmd_legacy[] = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
/* Note, mtime_only is not used here -- implemented as file option */
static char levelcmd[] = "level = %s%s%s mtime_only=%d\n";
static char runscript[] = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
@@ -114,13 +115,21 @@
}
/*
- * Now send JobId and authorization key
+ * Now send JobId and possible authorization key.
*/
- fd->fsend(jobcmd, edit_int64(jcr->JobId, ed1), jcr->Job, jcr->VolSessionId,
- jcr->VolSessionTime, jcr->sd_auth_key);
- if (strcmp(jcr->sd_auth_key, "dummy") != 0) {
- memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
+ if (jcr->FDVersion >= 2) {
+ fd->fsend(jobcmd, edit_int64(jcr->JobId, ed1), jcr->Job,
+ jcr->VolSessionId, jcr->VolSessionTime);
+ }
+ else {
+ /* jcr->FDVersion == 0, or 1 */
+ fd->fsend(jobcmd_legacy, edit_int64(jcr->JobId, ed1), jcr->Job,
+ jcr->VolSessionId, jcr->VolSessionTime, jcr->sd_auth_key);
+ if (strcmp(jcr->sd_auth_key, "dummy") != 0) {
+ memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
+ }
}
+
Dmsg1(100, ">filed: %s", fd->msg);
if (bget_dirmsg(fd) > 0) {
Dmsg1(110, "<filed: %s", fd->msg);
@@ -539,7 +548,8 @@
}
sock->fsend(bootstrap);
while (fgets(buf, sizeof(buf), bs)) {
- sock->fsend("%s", buf);
+ /* Storage daemons do not understand 'Storage=' lines! */
+ if (strncmp(buf, "Storage=", strlen("Storage="))) sock->fsend("%s", buf);
}
sock->signal(BNET_EOD);
fclose(bs);
Index: WORK/src/dird/protos.h
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/dird/protos.h,v
retrieving revision 1.2
diff -u -r1.2 protos.h
--- WORK/src/dird/protos.h 5 Jan 2009 17:03:05 -0000 1.2
+++ WORK/src/dird/protos.h 18 Mar 2009 17:17:55 -0000
@@ -53,6 +53,7 @@
/* backup.c */
extern int wait_for_job_termination(JCR *jcr, int timeout=0);
+extern int wait_for_job_termination_fd(JCR *jcr, int timeout=0);
extern bool do_backup_init(JCR *jcr);
extern bool do_backup(JCR *jcr);
extern void backup_cleanup(JCR *jcr, int TermCode);
Index: WORK/src/dird/restore.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/dird/restore.c,v
retrieving revision 1.1
diff -u -r1.1 restore.c
--- WORK/src/dird/restore.c 5 Jan 2009 16:06:53 -0000 1.1
+++ WORK/src/dird/restore.c 18 Mar 2009 17:17:55 -0000
@@ -52,54 +52,53 @@
/* Commands sent to File daemon */
static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
-static char storaddr[] = "storage address=%s port=%d ssl=0\n";
+static char endrestorecmd[] = "endrestore\n";
+static char storaddr[] = "storage address=%s port=%d ssl=0 Authorization=%s\n";
/* Responses received from File daemon */
static char OKrestore[] = "2000 OK restore\n";
static char OKstore[] = "2000 OK storage\n";
+static char OKstoreend[] = "2000 OK storage end\n";
static char OKbootstrap[] = "2000 OK bootstrap\n";
-/*
- * Do a restore of the specified files
- *
- * Returns: 0 on failure
- * 1 on success
- */
-bool do_restore(JCR *jcr)
+bool send_partial_bootstrap_file(JCR *jcr, BSOCK *sock, const char *storage, FILE *bs)
{
- BSOCK *fd;
- JOB_DBR rjr; /* restore job record */
- char replace, *where, *cmd;
- char empty = '\0';
- int stat;
+ fpos_t pos;
+ char buf[1000];
+ const char *bootstrap = "bootstrap\n";
+ UAContext *ua=NULL;
- free_wstorage(jcr); /* we don't write */
-
- if (!allow_duplicate_job(jcr)) {
- goto bail_out;
+ Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
+ if (!jcr->RestoreBootstrap) {
+ return true;
}
+ sock->fsend(bootstrap);
+ ua=new_ua_context(jcr);
+ while(!fgetpos(bs, &pos) && fgets(buf, sizeof(buf), bs)) {
+ Mmsg(ua->cmd, buf);
+ parse_ua_args(ua);
+ if(ua->argc!=1) continue;
+ if(ua->argk[0] && !strcasecmp(ua->argk[0], "Storage")) {
+ // Continue if this is a volume from the same storage.
+ if(ua->argv[0] && !strcmp(ua->argv[0], storage)) continue;
+ // Otherwise, we need to contact another storage daemon.
+ fsetpos(bs, &pos);
+ break;
+ }
- memset(&rjr, 0, sizeof(rjr));
- jcr->jr.JobLevel = L_FULL; /* Full restore */
- if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
- Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
- goto bail_out;
+ sock->fsend("%s", buf);
}
- Dmsg0(20, "Updated job start record\n");
-
- Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
-
- if (!jcr->RestoreBootstrap) {
- Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
- "You probably ran a restore job directly. All restore jobs must\n"
- "be run using the restore command.\n"));
- goto bail_out;
+ free_ua_context(ua);
+ sock->signal(BNET_EOD);
+ if (jcr->unlink_bsr) {
+ unlink(jcr->RestoreBootstrap);
+ jcr->unlink_bsr = false;
}
+ return true;
+}
-
- /* Print Job Start message */
- Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
-
+static int start_storage_daemon(JCR *jcr)
+{
/*
* Open a message channel connection with the Storage
* daemon. This is to let him know that our client
@@ -112,37 +111,32 @@
* Start conversation with Storage daemon
*/
if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
- goto bail_out;
+ return -1;
}
+
/*
* Now start a job with the Storage daemon
*/
if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
- goto bail_out;
+ return -1;
}
if (!jcr->store_bsock->fsend("run")) {
- goto bail_out;
+ return -1;
}
/*
* Now start a Storage daemon message thread
*/
if (!start_storage_daemon_message_thread(jcr)) {
- goto bail_out;
+ return -1;
}
Dmsg0(50, "Storage daemon connection OK\n");
+ return 0;
+}
- /*
- * Start conversation with File daemon
- */
- set_jcr_job_status(jcr, JS_WaitFD);
- if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
- goto bail_out;
- }
-
- fd = jcr->file_bsock;
- set_jcr_job_status(jcr, JS_Running);
-
+static int wait_for_fd_connect_to_sd(JCR *jcr)
+{
+ BSOCK *fd;
/*
* send Storage daemon address to the File daemon,
* then wait for File daemon to make connection
@@ -151,26 +145,25 @@
if (jcr->rstore->SDDport == 0) {
jcr->rstore->SDDport = jcr->rstore->SDport;
}
- fd->fsend(storaddr, jcr->rstore->address, jcr->rstore->SDDport);
+ fd = jcr->file_bsock;
+ fd->fsend(storaddr,
+ jcr->rstore->address, jcr->rstore->SDDport, jcr->sd_auth_key);
+ if(jcr->sd_auth_key) {
+ bfree(jcr->sd_auth_key);
+ jcr->sd_auth_key=NULL;
+ }
Dmsg1(6, "dird>filed: %s\n", fd->msg);
if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
- goto bail_out;
- }
-
- /*
- * Send the bootstrap file -- what Volumes/files to restore
- */
- if (!send_bootstrap_file(jcr, fd) ||
- !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
- goto bail_out;
- }
-
-
- if (!send_runscripts_commands(jcr)) {
- goto bail_out;
+ return -1;
}
+ return 0;
+}
- /* Send restore command */
+static int send_restore_command(JCR *jcr)
+{
+ BSOCK *fd;
+ char empty = '\0';
+ char replace, *where, *cmd;
if (jcr->replace != 0) {
replace = jcr->replace;
@@ -202,20 +195,239 @@
jcr->prefix_links = jcr->job->PrefixLinks;
bash_spaces(where);
+ fd = jcr->file_bsock;
fd->fsend(cmd, replace, jcr->prefix_links, where);
unbash_spaces(where);
if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
+ return -1;
+ }
+
+ /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
+ wait_for_storage_daemon_termination(jcr);
+
+ return 0;
+}
+
+static int do_storage(JCR *jcr, const char *storage, FILE *bs)
+{
+ BSOCK *fd;
+
+ if(!jcr->store_bsock && start_storage_daemon(jcr)) return -1;
+
+ if(wait_for_fd_connect_to_sd(jcr)) return -1;
+
+ /*
+ * Send the bootstrap file -- what Volumes/files to restore
+ */
+ fd = jcr->file_bsock;
+ if (!send_partial_bootstrap_file(jcr, fd, storage, bs) ||
+ !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
+ return -1;
+ }
+
+ if(send_restore_command(jcr)) return -1;
+
+ /* storage daemon status is in jcr->SDJobStatus; */
+
+ return 0;
+}
+
+static int single_bootstrap(JCR *jcr)
+{
+ BSOCK *fd;
+ /* storage daemon already started */
+
+ if(wait_for_fd_connect_to_sd(jcr)) return -1;
+
+ /*
+ * Send the bootstrap file -- what Volumes/files to restore
+ */
+ fd = jcr->file_bsock;
+ if (!send_bootstrap_file(jcr, fd) ||
+ !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
+ return -1;
+ }
+
+ if(send_restore_command(jcr)) return -1;
+
+ return 0;
+}
+
+static int loop_bootstrap(JCR *jcr)
+{
+ int ret=0;
+ FILE *bs=NULL;
+ char buf[1000];
+ int scount=0;
+ UAContext *ua=new_ua_context(jcr);
+ STORE *rstore=jcr->rstore;
+ bs=fopen(jcr->RestoreBootstrap, "rb");
+ if (!bs) {
+ berrno be;
+ Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
+ jcr->RestoreBootstrap, be.bstrerror());
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ return -1;
+ }
+
+ while(fgets(buf, sizeof(buf), bs)) {
+ USTORE ustore;
+ Mmsg(ua->cmd, buf);
+ parse_ua_args(ua);
+ if(ua->argc!=1
+ || (ua->argk[0] && strcasecmp(ua->argk[0], "Storage"))
+ || !ua->argv[0] || !*(ua->argv[0]))
+ continue;
+
+ /* We should already have connected to the first storage via the old
+ method of connecting to the storage daemon first, before connecting
+ to the file daemon.
+ So, only set up a new storage if we are past the first one.
+ */
+ if(scount > 0) {
+ if(!(ustore.store=(STORE *)GetResWithName(R_STORAGE, ua->argv[0]))) {
+ Jmsg(jcr, M_FATAL, 0,
+ _("Could not get storage resource '%s'.\n"), ua->argv[0]);
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ break;
+ }
+
+ free_rstorage(jcr);
+ set_rstorage(jcr, &ustore);
+
+ if(jcr->store_bsock) {
+ jcr->store_bsock->destroy();
+ jcr->store_bsock=NULL;
+ }
+ }
+
+ if(do_storage(jcr, ua->argv[0], bs)) {
+ Jmsg(jcr, M_FATAL, 0,
+ _("Restoring from storage '%s' failed.\n"), ua->argv[0]);
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ break;
+ }
+
+ /* storage daemon status is in jcr->SDJobStatus; */
+ if (jcr->SDJobStatus!=JS_Terminated) {
+ ret=-1;
+ break;
+ }
+
+ if (!response(jcr, jcr->file_bsock,
+ OKstoreend, "Storage end", DISPLAY_ERROR)) {
+ ret=-1;
+ break;
+ }
+
+ scount++;
+ }
+
+ fclose(bs);
+ free_ua_context(ua);
+ jcr->rstore=rstore;
+
+ return ret;
+}
+
+/*
+ * Do a restore of the specified files
+ *
+ * Returns: 0 on failure
+ * 1 on success
+ */
+bool do_restore(JCR *jcr)
+{
+ JOB_DBR rjr; /* restore job record */
+ int stat;
+
+ free_wstorage(jcr); /* we don't write */
+
+ if (!allow_duplicate_job(jcr)) {
goto bail_out;
}
- /* Wait for Job Termination */
- stat = wait_for_job_termination(jcr);
+ memset(&rjr, 0, sizeof(rjr));
+ jcr->jr.JobLevel = L_FULL; /* Full restore */
+ if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ goto bail_out;
+ }
+ Dmsg0(20, "Updated job start record\n");
+
+ Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
+
+ if (!jcr->RestoreBootstrap) {
+ Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
+ "You probably ran a restore job directly. All restore jobs must\n"
+ "be run using the restore command.\n"));
+ goto bail_out;
+ }
+
+ /* Print Job Start message */
+ Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
+
+ /* Old file daemons needed us to connect to the SD first, and get a
+ jcr->sd_auth_key. */
+ if(start_storage_daemon(jcr)) {
+ goto bail_out;
+ }
+
+ /*
+ * Start conversation with File daemon
+ */
+ set_jcr_job_status(jcr, JS_WaitFD);
+ if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
+ goto bail_out;
+ }
+ /* Once we have connected to the file daemon, we know what jcr->FDVersion
+ it is. */
+
+ set_jcr_job_status(jcr, JS_Running);
+
+ if (!send_runscripts_commands(jcr)) {
+ goto bail_out;
+ }
+
+ if (jcr->FDVersion >= 2) {
+ if (loop_bootstrap(jcr)) {
+ goto bail_out;
+ }
+ if (jcr->SDJobStatus!=JS_Terminated) {
+ goto bail_out;
+ }
+
+ jcr->file_bsock->fsend(endrestorecmd);
+
+ /* Wait for Job Termination */
+ stat = wait_for_job_termination_fd(jcr);
+ } else {
+ /* Legacy */
+ if (single_bootstrap(jcr)) {
+ goto bail_out;
+ }
+ /* Wait for Job Termination */
+ stat = wait_for_job_termination(jcr);
+ }
+
restore_cleanup(jcr, stat);
return true;
bail_out:
- restore_cleanup(jcr, JS_ErrorTerminated);
+ /* Need to make sure the FD is cleaned up */
+ BSOCK *fd = jcr->file_bsock;
+ if(jcr->file_bsock) {
+ fd->fsend("cancel Job=%s\n", jcr->Job);
+ while (fd->recv() >= 0) {
+ }
+ fd->signal(BNET_TERMINATE);
+ fd->close();
+ jcr->file_bsock = NULL;
+ }
+
+ // caller ends up doing its own restore_cleanup() when returning false.
+ //restore_cleanup(jcr, JS_ErrorTerminated);
return false;
}
Index: WORK/src/dird/verify.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/dird/verify.c,v
retrieving revision 1.1
diff -u -r1.1 verify.c
--- WORK/src/dird/verify.c 5 Jan 2009 16:06:53 -0000 1.1
+++ WORK/src/dird/verify.c 18 Mar 2009 17:17:55 -0000
@@ -48,7 +48,7 @@
/* Commands sent to File daemon */
static char verifycmd[] = "verify level=%s\n";
-static char storaddr[] = "storage address=%s port=%d ssl=0\n";
+static char storaddr[] = "storage address=%s port=%d ssl=0 Authorization=%s\n";
/* Responses received from File daemon */
static char OKverify[] = "2000 OK verify\n";
@@ -266,7 +266,8 @@
if (jcr->rstore->SDDport == 0) {
jcr->rstore->SDDport = jcr->rstore->SDport;
}
- bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport);
+ bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport,
+ jcr->sd_auth_key);
if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
goto bail_out;
}
Index: WORK/src/filed/authenticate.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/filed/authenticate.c,v
retrieving revision 1.1
diff -u -r1.1 authenticate.c
--- WORK/src/filed/authenticate.c 5 Jan 2009 16:06:53 -0000 1.1
+++ WORK/src/filed/authenticate.c 18 Mar 2009 17:17:55 -0000
@@ -42,8 +42,9 @@
/* Version at end of Hello
* prior to 10Mar08 no version
* 1 10Mar08
+ * 2 13Mar09 - added the ability to restore from multiple storages
*/
-static char OK_hello[] = "2000 OK Hello 1\n";
+static char OK_hello[] = "2000 OK Hello 2\n";
static char Dir_sorry[] = "2999 Authentication failed.\n";
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Index: WORK/src/filed/job.c
===================================================================
RCS file: /cvs/netpilot/GPL/bacula-2.5.28-b1/WORK/src/filed/job.c,v
retrieving revision 1.1
diff -u -r1.1 job.c
--- WORK/src/filed/job.c 5 Jan 2009 16:06:59 -0000 1.1
+++ WORK/src/filed/job.c 18 Mar 2009 17:17:55 -0000
@@ -63,6 +63,7 @@
static int level_cmd(JCR *jcr);
static int verify_cmd(JCR *jcr);
static int restore_cmd(JCR *jcr);
+static int end_restore_cmd(JCR *jcr);
static int storage_cmd(JCR *jcr);
static int session_cmd(JCR *jcr);
static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
@@ -97,6 +98,7 @@
{"JobId=", job_cmd, 0},
{"level = ", level_cmd, 0},
{"restore", restore_cmd, 0},
+ {"endrestore", end_restore_cmd, 0},
{"session", session_cmd, 0},
{"status", status_cmd, 1},
{".status", qstatus_cmd, 1},
@@ -112,8 +114,8 @@
};
/* Commands received from director that need scanning */
-static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
-static char storaddr[] = "storage address=%s port=%d ssl=%d";
+static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d";
+static char storaddr[] = "storage address=%s port=%d ssl=%d Authorization=%100s";
static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n";
static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
@@ -137,6 +139,7 @@
static char OKrestore[] = "2000 OK restore\n";
static char OKsession[] = "2000 OK session\n";
static char OKstore[] = "2000 OK storage\n";
+static char OKstoreend[] = "2000 OK storage end\n";
static char OKjob[] = "2000 OK Job %s (%s) %s,%s,%s";
static char OKsetdebug[] = "2000 OK setdebug=%d\n";
static char BADjob[] = "2901 Bad Job\n";
@@ -455,21 +458,15 @@
static int job_cmd(JCR *jcr)
{
BSOCK *dir = jcr->dir_bsock;
- POOLMEM *sd_auth_key;
- sd_auth_key = get_memory(dir->msglen);
if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job,
- &jcr->VolSessionId, &jcr->VolSessionTime,
- sd_auth_key) != 5) {
+ &jcr->VolSessionId, &jcr->VolSessionTime) != 4) {
pm_strcpy(jcr->errmsg, dir->msg);
Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
dir->fsend(BADjob);
- free_pool_memory(sd_auth_key);
return 0;
}
- jcr->sd_auth_key = bstrdup(sd_auth_key);
- free_pool_memory(sd_auth_key);
- Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
+ Dmsg1(120, "JobId=%d\n", jcr->JobId);
Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
new_plugins(jcr); /* instantiate plugins for this jcr */
generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
@@ -1363,16 +1360,29 @@
{
int stored_port; /* storage daemon port */
int enable_ssl; /* enable ssl to sd */
+ POOLMEM *sd_auth_key;
BSOCK *dir = jcr->dir_bsock;
BSOCK *sd; /* storage daemon bsock */
+ if(jcr->store_bsock) {
+ jcr->store_bsock->destroy();
+ jcr->store_bsock=NULL;
+ }
+
Dmsg1(100, "StorageCmd: %s", dir->msg);
- if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl) != 3) {
+ sd_auth_key = get_memory(dir->msglen);
+ if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port, &enable_ssl, sd_auth_key) != 4) {
pm_strcpy(jcr->errmsg, dir->msg);
Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
+ free_pool_memory(sd_auth_key);
goto bail_out;
}
- Dmsg3(110, "Open storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port, enable_ssl);
+
+ if(jcr->sd_auth_key) bfree(jcr->sd_auth_key);
+ jcr->sd_auth_key = bstrdup(sd_auth_key);
+ free_pool_memory(sd_auth_key);
+
+ Dmsg4(110, "Open storage: %s:%d ssl=%d %s\n", jcr->stored_addr, stored_port, enable_ssl, jcr->sd_auth_key);
/* Open command communications with Storage daemon */
/* Try to connect for 1 hour at 10 second intervals */
sd = bnet_connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
@@ -1765,12 +1775,26 @@
bail_out:
+ if (jcr->where) {
+ bfree(jcr->where);
+ jcr->where=NULL;
+ }
+
if (jcr->JobErrors) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
+ Dmsg0(130, "Done in job.c\n");
+ return 0;
}
Dmsg0(130, "Done in job.c\n");
+
+ /* Send OK to Director */
+ return dir->fsend(OKstoreend);
+}
+
+static int end_restore_cmd(JCR *jcr) {
generate_plugin_event(jcr, bEventEndRestoreJob);
+
return 0; /* return and terminate command loop */
}
--- WORK/src/dird/bsr.c 2009-03-18 15:24:47.000000000 +0000
+++ WORK/src/dird/bsr.c.sav 2009-03-18 15:22:32.000000000 +0000
@@ -251,12 +251,29 @@
return count;
}
+static void display_bsr_info_do(RBSR *bsr, UAContext *ua)
+{
+ char Device[MAX_NAME_LENGTH];
+ POOL_MEM volmsg(PM_MESSAGE);
+
+ for (int i=0; i < bsr->VolCount; i++) {
+ if (bsr->VolParams[i].VolumeName[0]) {
+ if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
+ Device[0] = 0;
+ }
+ Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
+ bsr->VolParams[i].VolumeName,
+ bsr->VolParams[i].Storage, Device);
+ add_prompt(ua, volmsg.c_str());
+ }
+ }
+}
+
void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
{
char *p;
POOL_MEM volmsg(PM_MESSAGE);
JobId_t JobId;
- char Device[MAX_NAME_LENGTH];
RBSR *bsr;
/* Tell the user what he will need to mount */
@@ -269,17 +286,7 @@
if (*rx.JobIds == 0) {
/* Print Volumes in any order */
for (bsr=rx.bsr; bsr; bsr=bsr->next) {
- for (int i=0; i < bsr->VolCount; i++) {
- if (bsr->VolParams[i].VolumeName[0]) {
- if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
- Device[0] = 0;
- }
- Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
- bsr->VolParams[i].VolumeName,
- bsr->VolParams[i].Storage, Device);
- add_prompt(ua, volmsg.c_str());
- }
- }
+ display_bsr_info_do(bsr, ua);
}
} else {
/* Ensure that the volumes are printed in JobId order */
@@ -288,17 +295,7 @@
if (JobId != bsr->JobId) {
continue;
}
- for (int i=0; i < bsr->VolCount; i++) {
- if (bsr->VolParams[i].VolumeName[0]) {
- if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
- Device[0] = 0;
- }
- Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
- bsr->VolParams[i].VolumeName,
- bsr->VolParams[i].Storage, Device);
- add_prompt(ua, volmsg.c_str());
- }
- }
+ display_bsr_info_do(bsr, ua);
}
}
}
@@ -315,6 +312,66 @@
return;
}
+static uint32_t write_bsr_volume(RBSR *bsr, UAContext *ua, RESTORE_CTX &rx, FILE *fd, bool *first, uint32_t *LastIndex)
+{
+ char ed1[50], ed2[50];
+ uint32_t count = 0;
+ uint32_t total_count = 0;
+ char device[MAX_NAME_LENGTH];
+
+ /*
+ * For a given volume, loop over all the JobMedia records.
+ * VolCount is the number of JobMedia records.
+ */
+ for (int i=0; i < bsr->VolCount; i++) {
+ if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
+ bsr->VolParams[i].LastIndex)) {
+ bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
+ continue;
+ }
+ if (!rx.store) {
+ find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
+ bsr->VolParams[i].MediaType);
+ }
+ fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
+ fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
+ fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
+ if (bsr->fileregex) {
+ fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
+ }
+ if (get_storage_device(device, bsr->VolParams[i].Storage)) {
+ fprintf(fd, "Device=\"%s\"\n", device);
+ }
+ if (bsr->VolParams[i].Slot > 0) {
+ fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
+ }
+ fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
+ fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
+ fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
+ edit_uint64(bsr->VolParams[i].EndAddr, ed2));
+// Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
+// bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
+
+ count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
+ bsr->VolParams[i].LastIndex, fd);
+ if (count) {
+ fprintf(fd, "Count=%u\n", count);
+ }
+ total_count += count;
+ /* If the same file is present on two tapes or in two files
+ * on a tape, it is a continuation, and should not be treated
+ * twice in the totals.
+ */
+ if (!*first && *LastIndex == bsr->VolParams[i].FirstIndex) {
+ total_count--;
+ }
+ *first = false;
+ *LastIndex = bsr->VolParams[i].LastIndex;
+ }
+ return total_count;
+}
+
+
/*
* Here we actually write out the details of the bsr file.
* Note, there is one bsr for each JobId, but the bsr may
@@ -325,123 +382,20 @@
*/
static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
{
- char ed1[50], ed2[50];
- uint32_t count = 0;
- uint32_t total_count = 0;
- uint32_t LastIndex = 0;
bool first = true;
+ uint32_t LastIndex = 0;
+ uint32_t total_count = 0;
char *p;
JobId_t JobId;
- char device[MAX_NAME_LENGTH];
RBSR *bsr;
if (*rx.JobIds == 0) {
- for (bsr=rx.bsr; bsr; bsr=bsr->next) {
- /*
- * For a given volume, loop over all the JobMedia records.
- * VolCount is the number of JobMedia records.
- */
- for (int i=0; i < bsr->VolCount; i++) {
- if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
- bsr->VolParams[i].LastIndex)) {
- bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
- continue;
- }
- if (!rx.store) {
- find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
- bsr->VolParams[i].MediaType);
- }
- fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
- fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
- fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
- if (bsr->fileregex) {
- fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
- }
- if (get_storage_device(device, bsr->VolParams[i].Storage)) {
- fprintf(fd, "Device=\"%s\"\n", device);
- }
- if (bsr->VolParams[i].Slot > 0) {
- fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
- }
- fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
- fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
- fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
- edit_uint64(bsr->VolParams[i].EndAddr, ed2));
- // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
- // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
-
- count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
- bsr->VolParams[i].LastIndex, fd);
- if (count) {
- fprintf(fd, "Count=%u\n", count);
- }
- total_count += count;
- /* If the same file is present on two tapes or in two files
- * on a tape, it is a continuation, and should not be treated
- * twice in the totals.
- */
- if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
- total_count--;
- }
- first = false;
- LastIndex = bsr->VolParams[i].LastIndex;
- }
- }
- return total_count;
+ for (bsr=rx.bsr; bsr; bsr=bsr->next)
+ total_count+=write_bsr_volume(bsr, ua, rx, fd, &first, &LastIndex);
}
- for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
+ else for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
for (bsr=rx.bsr; bsr; bsr=bsr->next) {
- if (JobId != bsr->JobId) {
- continue;
- }
- /*
- * For a given volume, loop over all the JobMedia records.
- * VolCount is the number of JobMedia records.
- */
- for (int i=0; i < bsr->VolCount; i++) {
- if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
- bsr->VolParams[i].LastIndex)) {
- bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
- continue;
- }
- if (!rx.store) {
- find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
- bsr->VolParams[i].MediaType);
- }
- fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
- fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
- fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
- if (bsr->fileregex) {
- fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
- }
- if (get_storage_device(device, bsr->VolParams[i].Storage)) {
- fprintf(fd, "Device=\"%s\"\n", device);
- }
- if (bsr->VolParams[i].Slot > 0) {
- fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
- }
- fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
- fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
- fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
- edit_uint64(bsr->VolParams[i].EndAddr, ed2));
- // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
- // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
-
- count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
- bsr->VolParams[i].LastIndex, fd);
- if (count) {
- fprintf(fd, "Count=%u\n", count);
- }
- total_count += count;
- /* If the same file is present on two tapes or in two files
- * on a tape, it is a continuation, and should not be treated
- * twice in the totals.
- */
- if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
- total_count--;
- }
- first = false;
- LastIndex = bsr->VolParams[i].LastIndex;
- }
+ if (JobId != bsr->JobId) continue;
+ total_count+=write_bsr_volume(bsr, ua, rx, fd, &first, &LastIndex);
}
}
return total_count;
------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Bacula-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bacula-devel