diff --git a/src/plugins/filed/BareosFdPluginBaseclass.py b/src/plugins/filed/BareosFdPluginBaseclass.py new file mode 100644 index 00000000000..48e71441eb2 --- /dev/null +++ b/src/plugins/filed/BareosFdPluginBaseclass.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Baseclass for Bareos python plugins +# Functions taken and adapted from bareos-fd.py +# (c) Bareos GmbH & Co. KG, Maik Aussendorf +# AGPL v.3 + +from bareosfd import * +from bareos_fd_consts import * +from os import O_WRONLY, O_CREAT + +class BareosFdPluginBaseclass: + ''' Bareos python plugin base class ''' + def __init__(self, context, plugindef): + DebugMessage(context, 100, "Constructor called in module " + __name__ + "\n"); + events = []; + events.append(bEventType['bEventJobEnd']); + events.append(bEventType['bEventEndBackupJob']); + events.append(bEventType['bEventEndFileSet']); + events.append(bEventType['bEventHandleBackupFile']); + RegisterEvents(context, events); + # get some static Bareos values + self.fdname = GetValue(context, bVariable['bVarFDName']); + self.jobId = GetValue(context, bVariable['bVarJobId']); + self.client = GetValue(context, bVariable['bVarClient']); + self.level = GetValue(context, bVariable['bVarLevel']); + self.jobName = GetValue(context, bVariable['bVarJobName']); + self.workingdir = GetValue(context, bVariable['bVarWorkingDir']); + DebugMessage(context, 100, "FDName = " + self.fdname + " - BareosFdPluginBaseclass\n"); + DebugMessage(context, 100, "WorkingDir = " + self.workingdir + " jobId: " + str(self.jobId) + "\n"); + + def parse_plugin_definition(self,context, plugindef): + DebugMessage(context, 100, "plugin def parser called with " + plugindef + "\n"); + # Parse plugin options into a dict + self.options = dict(); + plugin_options = plugindef.split(":"); + for current_option in plugin_options: + key,sep,val = current_option.partition("="); + DebugMessage(context, 100, "key:val: " + key + ':' + val + "\n"); + if val == '': + continue; + else: + self.options[key] = val; + # you should overload this method with your own and do option checking here, return bRCs['bRC_Error'], if options are not ok + # or better call super.parse_plugin_definition in your own class and make sanity check on self.options afterwards + return bRCs['bRC_OK']; + + + def plugin_io(self, context, IOP): + DebugMessage(context, 100, "plugin_io called with " + str(IOP) + "\n"); + + FNAME = IOP.fname; + if IOP.func == bIOPS['IO_OPEN']: + try: + if IOP.flags & (O_CREAT | O_WRONLY): + self.file = open(FNAME, 'wb'); + else: + self.file = open(FNAME, 'rb'); + except: + IOP.status = -1; + return bRCs['bRC_Error']; + + return bRCs['bRC_OK']; + + elif IOP.func == bIOPS['IO_CLOSE']: + self.file.close(); + return bRCs['bRC_OK']; + + elif IOP.func == bIOPS['IO_SEEK']: + return bRCs['bRC_OK']; + + elif IOP.func == bIOPS['IO_READ']: + IOP.buf = bytearray(IOP.count); + IOP.status = self.file.readinto(IOP.buf); + IOP.io_errno = 0 + return bRCs['bRC_OK']; + + elif IOP.func == bIOPS['IO_WRITE']: + IOP.status = self.file.write(IOP.buf); + IOP.io_errno = 0 + return bRCs['bRC_OK']; + + + def handle_plugin_event(self, context, event): + if event == bEventType['bEventJobEnd']: + DebugMessage(context, 100, "handle_plugin_event called with bEventJobEnd\n"); + + elif event == bEventType['bEventEndBackupJob']: + DebugMessage(context, 100, "handle_plugin_event called with bEventEndBackupJob\n"); + + elif event == bEventType['bEventEndFileSet']: + DebugMessage(context, 100, "handle_plugin_event called with bEventEndFileSet\n"); + + else: + DebugMessage(context, 100, "handle_plugin_event called with event" + str(event) + "\n"); + + return bRCs['bRC_OK']; + + + def start_backup_file(self,context, savepkt): + DebugMessage(context, 100, "start_backup called\n"); + # Base method, we do not add anything, overload this method with your implementation to add files to backup fileset + return bRCs['bRC_Skip']; + + + def end_backup_file(self, context): + DebugMessage(context, 100, "end_backup_file() entry point in Python called\n") + return bRCs['bRC_OK']; + + def start_restore_file(self, context, cmd): + DebugMessage(context, 100, "start_restore_file() entry point in Python called with" + str(cmd) + "\n") + return bRCs['bRC_OK']; + + def end_restore_file(self,context): + DebugMessage(context, 100, "end_restore_file() entry point in Python called\n") + return bRCs['bRC_OK']; + + def restore_object_data(self, context, ROP): + DebugMessage(context, 100, "restore_object_data called with " + str(ROP) + "\n"); + return bRCs['bRC_OK']; + + def create_file(self,context, restorepkt): + DebugMessage(context, 100, "create_file() entry point in Python called with" + str(restorepkt) + "\n") + restorepkt.create_status = bCFs['CF_EXTRACT']; + return bRCs['bRC_OK']; + + def check_file(self,context, fname): + DebugMessage(context, 100, "check_file() entry point in Python called with" + str(fname) + "\n") + return bRCs['bRC_OK']; + + def handle_backup_file(self,context, savepkt): + DebugMessage(context, 100, "handle_backup_file called with " + str(savepkt) + "\n"); + return bRCs['bRC_OK']; + +# vim: ts=4 tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/src/plugins/filed/BareosFdPluginLocalFileset.py b/src/plugins/filed/BareosFdPluginLocalFileset.py new file mode 100644 index 00000000000..0a6ad475c67 --- /dev/null +++ b/src/plugins/filed/BareosFdPluginLocalFileset.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Bareos python plugins class that adds files from a local list to the backup fileset +# (c) Bareos GmbH & Co. KG +# AGPL v.3 +# Author: Maik Aussendorf + +from bareosfd import * +from bareos_fd_consts import * +import os +from BareosFdPluginBaseclass import * +import BareosFdWrapper + + +class BareosFdPluginLocalFileset (BareosFdPluginBaseclass): + ''' + Simple Bareos-FD-Plugin-Class that parses a file and backups all files listed there + Filename is taken from plugin argument 'filename' + ''' + + def parse_plugin_definition(self,context, plugindef): + ''' + Parses the plugin argmuents and reads files from file given by argument 'filename' + ''' + BareosFdPluginBaseclass.parse_plugin_definition(self, context, plugindef); + if (not 'filename' in self.options): + DebugMessage(context, 100, "Option \'filename\' not defined.\n"); + return bRCs['bRC_Error']; + DebugMessage(context, 100, "Using " + self.options['filename'] + " to search for local files\n"); + if os.path.exists (self.options['filename']): + try: + config_file = open (self.options['filename'],'rb'); + except: + DebugMessage(context, 100, "Could not open file " + self.options['filename'] + "\n"); + return bRCs['bRC_Error']; + else: + DebugMessage(context, 100, "File " + self.options['filename'] + " does not exist\n"); + return bRCs['bRC_Error']; + self.files_to_backup = config_file.read().splitlines(); + return bRCs['bRC_OK']; + + + def start_backup_file(self,context, savepkt): + ''' + Defines the file to backup and creates the savepkt. In this example only files (no directories) + are allowed + ''' + DebugMessage(context, 100, "start_backup called\n"); + if not self.files_to_backup: + DebugMessage(context, 100, "No files to backup\n"); + return bRCs['bRC_Skip']; + + file_to_backup = self.files_to_backup.pop(); + DebugMessage(context, 100, "file: " + file_to_backup + "\n"); + + statp = StatPacket(); + savepkt.statp = statp; + savepkt.fname = file_to_backup; + savepkt.type = bFileType['FT_REG']; + + JobMessage(context, bJobMessageType['M_INFO'], "Starting backup of " + file_to_backup + "\n"); + return bRCs['bRC_OK']; + + def end_backup_file(self, context): + ''' + Here we return 'bRC_More' as long as our list files_to_backup is not empty and + bRC_OK when we are done + ''' + DebugMessage(context, 100, "end_backup_file() entry point in Python called\n") + if self.files_to_backup: + return bRCs['bRC_More']; + else: + return bRCs['bRC_OK']; + + +# vim: ts=4 tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/src/plugins/filed/BareosFdWrapper.py b/src/plugins/filed/BareosFdWrapper.py new file mode 100644 index 00000000000..687354ab15e --- /dev/null +++ b/src/plugins/filed/BareosFdWrapper.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# The BareosFdWrapper module. Here is a global object bareos_fd_plugin_object and wrapper functions, which +# are directly called out of the bareos-fd. They are intended to pass the call to a method of an +# object of type BareosFdPluginBaseclass (or derived) + +# use this as global plugin object among your python-fd-plugin modules +bareos_fd_plugin_object=None + +def parse_plugin_definition(context, plugindef): + return bareos_fd_plugin_object.parse_plugin_definition(context, plugindef); + +def handle_plugin_event(context, event): + return bareos_fd_plugin_object.handle_plugin_event(context, event); + +def start_backup_file(context, savepkt): + return bareos_fd_plugin_object.start_backup_file(context, savepkt); + +def end_backup_file(context): + return bareos_fd_plugin_object.end_backup_file(context); + +def start_restore_file(context, cmd): + return bareos_fd_plugin_object.start_restore_file(context,cmd); + +def end_restore_file(context): + return bareos_fd_plugin_object.end_restore_file(context); + +def restore_object_data(context, ROP): + return bareos_fd_plugin_object.restore_object_data(context, ROP); + +def plugin_io(context, IOP): + return bareos_fd_plugin_object.plugin_io(context, IOP); + +def create_file(context, restorepkt): + return bareos_fd_plugin_object.create_file(context, restorepkt) + +def check_file(context, fname): + return bareos_fd_plugin_object.check_file(context, fname) + +def handle_backup_file(context, savepkt): + return bareos_fd_plugin_object.handle_backup_file(context, savepkt) diff --git a/src/plugins/filed/bareos-fd-local-fileset.py b/src/plugins/filed/bareos-fd-local-fileset.py new file mode 100644 index 00000000000..d5d82ed2b16 --- /dev/null +++ b/src/plugins/filed/bareos-fd-local-fileset.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Bareos-fd-local-fileset a simple example for a python Bareos FD Plugin using BareosFdPluginLocalFileset +# The plugin argument 'filename' is used to read all files listed in that file and add it to the fileset + +# Provided by the Bareos FD Python plugin interface +from bareosfd import * +from bareos_fd_consts import * + +# This module contains the wrapper functions called by the Bareos-FD, the functions call the corresponding +# methods from your plugin class +from BareosFdWrapper import * + +# This module contains the used plugin class +from BareosFdPluginLocalFileset import * + +def load_bareos_plugin(context, plugindef): + ''' + This function is called by the Bareos-FD to load the plugin + We use it to instantiate the plugin class + ''' + # BareosFdWrapper.bareos_fd_plugin_object is the module attribute that holds the plugin class object + BareosFdWrapper.bareos_fd_plugin_object = BareosFdPluginLocalFileset (context, plugindef); + return bRCs['bRC_OK']; + +# the rest is done in the Plugin module diff --git a/src/plugins/filed/bareos-fd-mock-test.py b/src/plugins/filed/bareos-fd-mock-test.py new file mode 100644 index 00000000000..0385b0b0a23 --- /dev/null +++ b/src/plugins/filed/bareos-fd-mock-test.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Bareos-fd-mock-test a simple example for a python Bareos FD Plugin using the baseclass +# and doing nothing +# You may take this as a skeleton for your plugin + +from bareosfd import * +from bareos_fd_consts import * +from os import O_WRONLY, O_CREAT + +from BareosFdPluginBaseclass import * +from BareosFdWrapper import * + +def load_bareos_plugin(context, plugindef): + DebugMessage(context, 100, "------ Plugin loader called with " + plugindef + "\n"); + BareosFdWrapper.plugin_object = BareosFdPluginBaseclass (context, plugindef); + return bRCs['bRC_OK']; + +# the rest is done in the Plugin module