]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
Fix #1868 Make StorageGroup feature compatible with Copy and Migration jobs
authorEric Bollengier <eric@baculasystems.com>
Fri, 22 Apr 2022 16:21:25 +0000 (18:21 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 14 Sep 2023 11:56:58 +0000 (13:56 +0200)
bacula/src/dird/bsr.c
bacula/src/dird/bsr.h
bacula/src/dird/mac.c
bacula/src/dird/restore.c

index e25618b17b1bb5b216dfc4b7032714e1612228b3..ac3a8f1a6951a56c84ebb4d2f5d13289157063d9 100644 (file)
@@ -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;
+   }
+}
index 6bacb8da820b45cf347acccc7d557f0bf23b0442..732dadae7b7ee5de476a3bb971fbfdd6e94049b3 100644 (file)
@@ -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
index fc588b8e1ef334289faf54dbf8554046f1082ba7..72b14f7830db804181ad77ff11eeecce5b8e4baa 100644 (file)
@@ -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
     */
index e82e3c479fb7408f28c05973bf50e52c49817fe0..c6c491140b115490ad194c3e1188ddc2854fd0d7 100644 (file)
@@ -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