]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
metaplugin: Add checkFile() callback.
authorRadosław Korzeniewski <radoslaw@korzeniewski.net>
Wed, 7 Apr 2021 15:33:41 +0000 (17:33 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 24 Mar 2022 08:03:01 +0000 (09:03 +0100)
bacula/src/plugins/fd/pluginlib/Makefile
bacula/src/plugins/fd/pluginlib/metaplugin.cpp
bacula/src/plugins/fd/pluginlib/metaplugin.h
bacula/src/plugins/fd/pluginlib/metaplugin_test.cpp [new file with mode: 0644]
bacula/src/plugins/fd/pluginlib/pluginlib.h

index b890b46cebe5b8135c72c0545d7b17df81db8f5e..c5172670f69fb6f09a731ac30200aa034edab66b 100644 (file)
@@ -11,6 +11,7 @@ include ../Makefile.inc
 
 UNITTESTSOBJ = $(LIBDIR)/unittests.lo
 LIBBACOBJ = $(LIBDIR)/libbac.la
+LIBBACCFGOBJ = $(LIBDIR)/libbaccfg.la
 
 PLUGINLIBSSRC = pluginlib.cpp pluginlib.h
 PLUGINLIBSOBJ = $(filter %.lo,$(PLUGINLIBSSRC:.cpp=.lo))
@@ -36,6 +37,8 @@ SMARTALISTTEST = smartalist_test.cpp $(SMARTALISTSRC) $(PLUGINLIBSOBJ) $(UNITTES
 SMARTALISTTESTOBJ = $(filter %.lo,$(SMARTALISTTEST:.cpp=.lo))
 SMARTPTRTEST = smartptr_test.cpp $(SMARTPTRSRC) $(PLUGINLIBSOBJ) $(UNITTESTSOBJ)
 SMARTPTRTESTOBJ = $(filter %.lo,$(SMARTPTRTEST:.cpp=.lo))
+METAPLUGINTEST = metaplugin_test.cpp $(METAPLUGINSRC)
+METAPLUGINTESTOBJ = $(filter %.lo,$(METAPLUGINTEST:.cpp=.lo)) $(PTCOMMOBJ) $(PLUGINLIBSOBJ) $(METAPLUGINOBJ) $(UNITTESTSOBJ)
 
 TESTMETAPLUGINBACKENDSRC = test_metaplugin_backend.c
 TESTMETAPLUGINBACKENDOBJ = $(TESTMETAPLUGINBACKENDSRC:.c=.lo)
@@ -67,7 +70,10 @@ $(UNITTESTSOBJ):
 $(LIBBACOBJ):
        $(MAKE) -C $(LIBDIR) libbac.la
 
-test_metaplugin_backend.lo: Makefile $(TESTMETAPLUGINBACKENDSRC)
+$(LIBBACCFGOBJ):
+       $(MAKE) -C $(LIBDIR) libbaccfg.la
+
+test_metaplugin_backend.lo: $(TESTMETAPLUGINBACKENDSRC)
        @echo "Compiling backend $< ..."
        $(NO_ECHO)$(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) $(CPPFLAGS) $(CFLAGS) -I${SRCDIR} -I${FDDIR} -DLOGDIR=\"$(DESTDIR)$(working_dir)\" -c $<
 
@@ -91,6 +97,12 @@ iso8601_test: Makefile $(ISO8601TESTOBJ) $(ISO8601SRC) $(UNITTESTSOBJ) $(LIBBACO
        @echo "Building $@ ..."
        $(NO_ECHO)$(LIBTOOL_LINK) --silent $(CXX) $(LDFLAGS) -L$(LIBDIR) -lbac $(PLUGINLIBSTESTOBJ) -o $@
 
+metaplugin_test: $(METAPLUGINTESTOBJ) $(LIBBACOBJ)
+       @echo "Building $@ ..."
+       $(LIBTOOL_LINK) --silent $(CXX) $(LDFLAGS) -L$(LIBDIR) $(LIBBACCFGOBJ) $(LIBBACOBJ) $(METAPLUGINTESTOBJ) -o $@
+
+#$(NO_ECHO)
+
 install: all
        $(MKDIR) $(DESTDIR)$(plugindir)
 
index 2982e1bb12cb3b7f366ecfe6a969521832ee9d54..852c48d2de2607856ace3b4840fa3492820afe9b 100644 (file)
@@ -61,7 +61,7 @@ static bRC startRestoreFile(bpContext *ctx, const char *cmd);
 static bRC endRestoreFile(bpContext *ctx);
 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
-// Not used! static bRC checkFile(bpContext *ctx, char *fname);
+static bRC metaplugincheckFile(bpContext *ctx, char *fname);
 static bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl);
 static bRC queryParameter(bpContext *ctx, struct query_pkt *qp);
 static bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp);
@@ -88,7 +88,7 @@ static pFuncs pluginFuncs =
    pluginIO,
    createFile,
    setFileAttributes,
-   NULL,
+   metaplugincheckFile,
    handleXACLdata,
    NULL,                        /* No restore file list */
    NULL,                        /* No checkStream */
@@ -165,7 +165,6 @@ METAPLUGIN::METAPLUGIN(bpContext *bpctx) :
       pluginobjectsent(false),
       readacl(false),
       readxattr(false),
-      accurate_warning(false),
       fname(PM_FNAME),
       lname(PM_FNAME),
       robjbuf(NULL),
@@ -2428,7 +2427,6 @@ bRC METAPLUGIN::metadataRestore(bpContext *ctx, struct meta_pkt *mp)
 
    if (mp->buf != NULL && mp->buf_len > 0){
       /* send command METADATA */
-      // pm_strcpy(cmd, "METADATA_STREAM\n");
       pm_strcpy(cmd, prepare_metadata_type(mp->type));
       backend.ctx->write_command(ctx, cmd.c_str());
       /* send metadata stream data */
@@ -2447,6 +2445,28 @@ bRC METAPLUGIN::metadataRestore(bpContext *ctx, struct meta_pkt *mp)
    return bRC_OK;
 }
 
+/**
+ * @brief Implements default metaplugin checkFile() callback.
+ *    When fname match plugin configured namespace then it return bRC_Seen by default
+ *    or calls custom checkFile() callback defined by backend developer.
+ *
+ * @param ctx for Bacula debug and jobinfo messages
+ * @param fname file name to check
+ * @return bRC bRC_Seen or bRC_OK
+ */
+bRC METAPLUGIN::checkFile(bpContext * ctx, char *fname)
+{
+   if ((!CUSTOMNAMESPACE && isourpluginfname(PLUGINPREFIX, fname)) || (CUSTOMNAMESPACE && isourpluginfname(PLUGINNAMESPACE, fname)))
+   {
+      if (::checkFile != NULL){
+         return ::checkFile(ctx, fname);
+      }
+      return bRC_Seen;
+   }
+
+   return bRC_OK;
+}
+
 /*
  * Called here to make a new instance of the plugin -- i.e. when
  * a new Job is started.  There can be multiple instances of
@@ -2665,3 +2685,17 @@ static bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp)
    METAPLUGIN *self = pluginclass(ctx);
    return self->metadataRestore(ctx, mp);
 }
+
+/*
+ * checkFile used for accurate mode backup
+ *
+ * TODO: currently it is not working because a checking is performed against ldap plugin, not msad
+ */
+static bRC metaplugincheckFile(bpContext * ctx, char *fname)
+{
+   ASSERT_CTX;
+
+   DMSG(ctx, D3, "checkFile for: %s\n", fname);
+   METAPLUGIN *self = pluginclass(ctx);
+   return self->checkFile(ctx, fname);
+}
index 167b4d85aea737ba3a785daea9b1c8dd468a588b..f17fcabf24874e1d9706ab1f41bbfea2c4845f8f 100644 (file)
@@ -55,6 +55,10 @@ extern const bool CUSTOMNAMESPACE;
 extern const char *PLUGINAPI;
 extern const char *BACKEND_CMD;
 
+// custom checkFile() callback
+typedef bRC (*checkFile_t)(bpContext *ctx, char *fname);
+extern checkFile_t checkFile;
+
 // The list of restore options saved to the RestoreObject.
 extern struct ini_items plugin_items_dump[];
 
@@ -101,6 +105,7 @@ public:
    bRC pluginIO(bpContext *ctx, struct io_pkt *io);
    bRC createFile(bpContext *ctx, struct restore_pkt *rp);
    bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
+   bRC checkFile(bpContext *ctx, char *fname);
    bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl);
    bRC queryParameter(bpContext *ctx, struct query_pkt *qp);
    bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp);
@@ -142,7 +147,6 @@ private:
    bool pluginobjectsent;        // set when startBackupFile handled plugin object and endBackupFile has to check for nextfile
    bool readacl;                 // got ACL data from backend
    bool readxattr;               // got XATTR data from backend
-   bool accurate_warning;        // for sending accurate mode warning once */
    COMMCTX<PTCOMM> backend;      // the backend context list for multiple backend execution for a single job
    POOL_MEM fname;               // current file name to backup (grabbed from backend)
    POOL_MEM lname;               // current LSTAT data if any
diff --git a/bacula/src/plugins/fd/pluginlib/metaplugin_test.cpp b/bacula/src/plugins/fd/pluginlib/metaplugin_test.cpp
new file mode 100644 (file)
index 0000000..ff0391b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2020 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+/**
+ * @file metaplugin_tests.cpp
+ * @author Radosław Korzeniewski (radoslaw@korzeniewski.net)
+ * @brief This is a Bacula metaplugin unittests
+ * @version 1.0.0
+ * @date 2021-04-07
+ *
+ * @copyright Copyright (c) 2021 All rights reserved.
+ *            IP transferred to Bacula Systems according to agreement.
+ */
+
+#include "metaplugin.h"
+#include "bacula.h"
+#include "unittests.h"
+
+/* Plugin Info definitions */
+const char *PLUGIN_LICENSE       = "AGPLv3";
+const char *PLUGIN_AUTHOR        = "Radoslaw Korzeniewski";
+const char *PLUGIN_DATE          = "April 2021";
+const char *PLUGIN_VERSION       = "1.0.0";
+const char *PLUGIN_DESCRIPTION   = "Bacula Enterprise MetaPlugin";
+
+/* Plugin compile time variables */
+const char *PLUGINPREFIX         = "metaplugin:";
+const char *PLUGINNAME           = "metaplugin";
+const char *PLUGINNAMESPACE      = "@metaplugin";
+const bool CUSTOMNAMESPACE       = true;
+const char *PLUGINAPI            = "3";
+const char *BACKEND_CMD          = "/bin/true";
+
+static bRC mycheckFile(bpContext *ctx, char *fname);
+checkFile_t checkFile = NULL;
+// checkFile_t checkFile = mycheckFile;
+
+struct ini_items plugin_items_dump[] = { {NULL, NULL, NULL, 0, NULL} };
+const char * valid_params[] = { NULL };
+
+#ifdef DEVELOPER
+const metadataTypeMap plugin_metadata_map[] = {{"METADATA_STREAM", plugin_meta_blob}};
+#else
+const metadataTypeMap plugin_metadata_map[] = {{NULL, plugin_meta_invalid}};
+#endif
+
+/* In order to link with libbaccfg */
+int32_t r_last;
+int32_t r_first;
+RES_HEAD **res_head;
+bool save_resource(RES_HEAD **rhead, int type, RES_ITEM *items, int pass){return false;}
+bool save_resource(CONFIG*, int, RES_ITEM*, int) {return false;}
+void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock){}
+void free_resource(RES *rres, int type){}
+union URES {};
+RES_TABLE resources[] = {};
+URES res_all;
+
+static bRC mycheckFile(bpContext *ctx, char *fname)
+{
+   return bRC_Error;
+}
+
+struct vectstruct
+{
+   const char *fname;
+   bRC status;
+};
+
+static const vectstruct testvect1[] = {
+   {"/etc/passwd", bRC_OK},
+   {"/@MYSQL/", bRC_OK},
+   {"/@metaplugin/test/file", bRC_Seen},
+   {"/@kubernetes/namespace/test", bRC_OK},
+   {"@metaplugin/other", bRC_Seen},
+   {"test/file", bRC_OK},
+   {NULL, bRC_Error},
+};
+
+int main()
+{
+   Unittests metaplugin_test("metaplugin_test");
+
+   struct bpContext bpctx = {};
+   bpContext *bpctxp = &bpctx;
+   POOL_MEM testfname(PM_FNAME);
+   METAPLUGIN mp(bpctxp);
+
+   for (int i = 0; testvect1[i].fname != NULL; i++){
+      pm_strcpy(testfname, testvect1[i].fname);
+      bRC status = mp.checkFile(bpctxp, testfname.c_str());
+      ok(status == testvect1[i].status, testfname.c_str());
+   }
+
+   checkFile = mycheckFile;
+   pm_strcpy(testfname, "@metaplugin/");
+   ok(mp.checkFile(bpctxp, testfname.c_str()) == bRC_Error, "custom mycheckFile()");
+}
index 0c79cc56ef4798bab0a9f83426c0fcbfd886e80e..cf6567fd90b806a2ceff254c5ef003e10ee06db5 100644 (file)
@@ -156,6 +156,31 @@ inline bool isourplugincommand(const char *pluginprefix, const char *command)
    return false;
 }
 
+/**
+ * @brief Checks if fname is a part of pluginprefix namespace
+ *
+ * @param pluginprefix plugin namespace prefix
+ * @param fname file name to check
+ * @return true when it matches
+ * @return false when not
+ */
+inline bool isourpluginfname(const char *pluginprefix, const char *fname)
+{
+   /* check if it is our Plugin fname */
+   if (strncmp(pluginprefix, fname, strlen(pluginprefix)) == 0){
+      return true;
+   }
+   char _fn[strlen(pluginprefix) + 2];
+   _fn[0] = '/';
+   _fn[1] = '\0';
+   strcat(_fn, pluginprefix);
+   if (strncmp(_fn, fname, strlen(_fn)) == 0){
+      return true;
+   }
+
+   return false;
+}
+
 alist * plugutil_str_split_to_alist(const char * str, const char sep = '.');
 
 /* plugin parameters manipulation */