From: Eric Bollengier Date: Fri, 22 Apr 2022 16:21:25 +0000 (+0200) Subject: Fix #1868 Make StorageGroup feature compatible with Copy and Migration jobs X-Git-Tag: Beta-15.0.0~591 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4deaa287a55c73f3c22427540090f6f8cefaa2cd;p=thirdparty%2Fbacula.git Fix #1868 Make StorageGroup feature compatible with Copy and Migration jobs --- diff --git a/bacula/src/dird/bsr.c b/bacula/src/dird/bsr.c index e25618b17..ac3a8f1a6 100644 --- a/bacula/src/dird/bsr.c +++ b/bacula/src/dird/bsr.c @@ -761,3 +761,64 @@ void scan_bsr(JCR *jcr) } return; } + +/** + * Open the bootstrap file and find the first Storage= + * Returns ok if able to open + * It fills the storage name (should be the first line) + * and the file descriptor to the bootstrap file, + * it should be used for next operations, and need to be closed + * at the end. + */ +bool open_bootstrap_file(JCR *jcr, bootstrap_info &info) +{ + FILE *bs; + UAContext *ua; + info.bs = NULL; + info.ua = NULL; + + if (!jcr->RestoreBootstrap) { + return false; + } + bstrncpy(info.storage, jcr->store_mngr->get_rstore()->name(), MAX_NAME_LENGTH); + + bs = bfopen(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()); + jcr->setJobStatus(JS_ErrorTerminated); + return false; + } + + ua = new_ua_context(jcr); + while (bfgets(ua->cmd, bs)) { + parse_ua_args(ua); + if (ua->argc != 1) { + continue; + } + if (!strcasecmp(ua->argk[0], "Storage")) { + bstrncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH); + break; + } + } + info.bs = bs; + info.ua = ua; + fseek(bs, 0, SEEK_SET); /* return to the top of the file */ + return true; +} + +/* + * Clean the bootstrap_info struct + */ +void close_bootstrap_file(bootstrap_info &info) +{ + if (info.bs) { + fclose(info.bs); + info.bs = NULL; + } + if (info.ua) { + free_ua_context(info.ua); + info.ua = NULL; + } +} diff --git a/bacula/src/dird/bsr.h b/bacula/src/dird/bsr.h index 6bacb8da8..732dadae7 100644 --- a/bacula/src/dird/bsr.h +++ b/bacula/src/dird/bsr.h @@ -25,7 +25,8 @@ * Kern Sibbald, July MMII */ - +#ifndef BSR_H +#define BSR_H /* FileIndex entry in restore bootstrap record */ struct RBSR_FINDEX { @@ -55,3 +56,19 @@ struct RBSR { /* If we extend an existing fi, keep the memory for the next insert */ RBSR_FINDEX *m_fi; }; + + +class UAContext; +/* Structure used to quickly scan the BSR file and find + * the right storage daemon to connect to + */ +struct bootstrap_info +{ + FILE *bs; + UAContext *ua; + char storage[MAX_NAME_LENGTH+1]; +}; +bool open_bootstrap_file(JCR *jcr, bootstrap_info &info); +void close_bootstrap_file(bootstrap_info &info); + +#endif diff --git a/bacula/src/dird/mac.c b/bacula/src/dird/mac.c index fc588b8e1..72b14f783 100644 --- a/bacula/src/dird/mac.c +++ b/bacula/src/dird/mac.c @@ -380,7 +380,7 @@ bool do_mac(JCR *jcr) BSOCK *sd, *wsd; JCR *wjcr = jcr->wjcr; /* newly migrated job */ bool ok = false; - STORE *store; + STORE *store, *bsr_store; char *store_address; uint32_t store_port; STORE *rstore = NULL; @@ -458,6 +458,70 @@ bool do_mac(JCR *jcr) jcr->setJobStatus(JS_WaitSD); wjcr->setJobStatus(JS_WaitSD); + if (jcr->store_mngr->get_rstore_list()->size() > 1) { + POOL_MEM src; + /* To help the user, we can check if the selected storage is compatible + * with what we have in the BSR + */ + bootstrap_info info; + if (!open_bootstrap_file(jcr, info)) { // We get the first Storage= + goto bail_out; + } + close_bootstrap_file(info); + + /* Keep the source of the information */ + pm_strcpy(src, jcr->store_mngr->get_rsource()); + + /* If we have a Storage Group defined, we can look into it + * TODO: Like for Backup, we can also check for the different algorithms + * (least used, round robbin) + */ + bsr_store = (STORE *)GetResWithName(R_STORAGE, info.storage); + if (bsr_store) { + bool found=false; + foreach_alist(store, jcr->store_mngr->get_rstore_list()) { + /* At least the Address and the Port should match */ + if (strcmp(store->address, bsr_store->address) == 0 && store->SDport == bsr_store->SDport) { + /* The storage is ok, it will select it */ + jcr->store_mngr->set_rstore(store, src.c_str()); + found=true; + break; + } + } + if (!found) { + /* Maybe we can find a storage with the right name. Should not happen */ + foreach_alist(store, jcr->store_mngr->get_rstore_list()) { + if (strcmp(store->hdr.name, info.storage) == 0) { + jcr->store_mngr->set_rstore(store, src.c_str()); + found=true; + break; + } + } + } + if (!found) { + /* Let's try with the MediaType */ + foreach_alist(store, jcr->store_mngr->get_rstore_list()) { + if (strcmp(store->media_type, bsr_store->media_type) == 0) { + /* The Media type is the same, it will select it */ + jcr->store_mngr->set_rstore(store, src.c_str()); + break; + } + } + } + /* TODO: It is possible to iterate on the global list of Storage + * resource and pick the original one, it would solve automatically + * any configuration issues. + */ + if (!found) { + Jmsg(jcr, M_WARNING, 0, _("Could not find a compatible Storage to read volumes in the %s Job definition (%s/%s)\n"), + jcr->job->name(), bsr_store->hdr.name, bsr_store->media_type); + } + + } else { + Dmsg1(50, "Unable to find the Storage resource \"%s\" in the configuration\n", info.storage); + } + } + /* * Start conversation with write Storage daemon */ diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index e82e3c479..c6c491140 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -120,62 +120,6 @@ static void build_restore_command(JCR *jcr, POOL_MEM &ret) unbash_spaces(where.c_str()); } -struct bootstrap_info -{ - FILE *bs; - UAContext *ua; - char storage[MAX_NAME_LENGTH+1]; -}; - -#define UA_CMD_SIZE 1000 - -/** - * Open the bootstrap file and find the first Storage= - * Returns ok if able to open - * It fills the storage name (should be the first line) - * and the file descriptor to the bootstrap file, - * it should be used for next operations, and need to be closed - * at the end. - */ -static bool open_bootstrap_file(JCR *jcr, bootstrap_info &info) -{ - FILE *bs; - UAContext *ua; - info.bs = NULL; - info.ua = NULL; - - if (!jcr->RestoreBootstrap) { - return false; - } - bstrncpy(info.storage, jcr->store_mngr->get_rstore()->name(), MAX_NAME_LENGTH); - - bs = bfopen(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()); - jcr->setJobStatus(JS_ErrorTerminated); - return false; - } - - ua = new_ua_context(jcr); - ua->cmd = check_pool_memory_size(ua->cmd, UA_CMD_SIZE+1); - while (!fgets(ua->cmd, UA_CMD_SIZE, bs)) { - parse_ua_args(ua); - if (ua->argc != 1) { - continue; - } - if (!strcasecmp(ua->argk[0], "Storage")) { - bstrncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH); - break; - } - } - info.bs = bs; - info.ua = ua; - fseek(bs, 0, SEEK_SET); /* return to the top of the file */ - return true; -} - /** * This function compare the given storage name with the * the current one. We compare the name and the address:port. @@ -265,7 +209,7 @@ static bool send_bootstrap_file(JCR *jcr, BSOCK *sock, } sock->fsend(bootstrap); pos = ftello(bs); - while(fgets(ua->cmd, UA_CMD_SIZE, bs)) { + while(bfgets(ua->cmd, bs)) { if (check_for_new_storage(jcr, info)) { /* Otherwise, we need to contact another storage daemon. * Reset bs to the beginning of the current segment. @@ -337,19 +281,6 @@ static bool select_rstore(JCR *jcr, bootstrap_info &info) return false; } -/* - * Clean the bootstrap_info struct - */ -static void close_bootstrap_file(bootstrap_info &info) -{ - if (info.bs) { - fclose(info.bs); - } - if (info.ua) { - free_ua_context(info.ua); - } -} - /** * The bootstrap is stored in a file, so open the file, and loop * through it processing each storage device in turn. If the