UNITTESTSOBJ = $(LIBDIR)/unittests.lo
LIBBACOBJ = $(LIBDIR)/libbac.la
+LIBBACCFGOBJ = $(LIBDIR)/libbaccfg.la
PLUGINLIBSSRC = pluginlib.cpp pluginlib.h
PLUGINLIBSOBJ = $(filter %.lo,$(PLUGINLIBSSRC:.cpp=.lo))
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)
$(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 $<
@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)
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);
pluginIO,
createFile,
setFileAttributes,
- NULL,
+ metaplugincheckFile,
handleXACLdata,
NULL, /* No restore file list */
NULL, /* No checkStream */
pluginobjectsent(false),
readacl(false),
readxattr(false),
- accurate_warning(false),
fname(PM_FNAME),
lname(PM_FNAME),
robjbuf(NULL),
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 */
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
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);
+}
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[];
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);
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
--- /dev/null
+/*
+ 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()");
+}
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 */