class Params(object): required_params = ['mount_base', 'device'] optional_params = ['debug', 'log_to_stdout', 'config', 'host', 'disk', 'layer_param_field_sep', 'level', 'execute_where'] interesting_params = ['device', 'disk', 'mount_base', 'debug', 'log_to_stdout', 'layer_param_field_sep'] # Make this a class property so other modules can add options options = OptionParser( usage="usage: %prog [execute-on]+ [options]", description="Amanda backup script plugin for backing up " \ "volume snapshots", epilog="See the README file or " \ "https://github.com/zultron/amanda-snapshot-layers " \ "for more information" ) @property def all_params(self): return self.required_params + self.optional_params @classmethod def add_option(cls, *args, **kwargs): """ Add a command-line option. Arguments are passed directly to 'OptionParser.add_option()', except 'required_param' (default False) and 'interesting_param' (default True). """ required_param = kwargs.pop('required_param',False) interesting_param = kwargs.pop('interesting_param',True) opt = cls.options.add_option(*args,**kwargs) if required_param: cls.required_params.append(opt.dest) else: cls.optional_params.append(opt.dest) if interesting_param: cls.interesting_params.append(opt.dest) def __init__(self, set_up_entry_points, tear_down_entry_points): self.set_up_entry_points = set_up_entry_points self.tear_down_entry_points = tear_down_entry_points # basic command line option parsing and sanity checks self.parse_options() self.check_args() self.check_required_params() self.check_device_param() self.util = Util(debug=self.debug, logfile = self.logfile, log_to_stdout = self.log_to_stdout) def parse_options(self): # custom properties self.options.add_option( "--mount_base", "--mount-base", help=("base directory to mount snapshot")) self.options.add_option( "--debug", type="int", help=("Print debug output; param is 0 or 1")) self.options.add_option( "--log_to_stdout", "--log-to-stdout", action="store_true", default=False, help=("output to stdout for debugging")) self.options.add_option( "--layer_param_field_sep", "--layer-param-field-sep", default=',=+', help=("separator charactors for layers, params and fields " "(default ',=+')")) self.options.add_option( "--snaplayers_log_pattern", "--snaplayers-log-pattern", default=LOG_FILE_PAT, help=("snapshot log file pattern; default: %s" % LOG_FILE_PAT)) # standard properties self.options.add_option( "--device", help=("mount directory with embedded device layering scheme: " "<mount_base>/(lvm=<vg+lv>|raid1|part=<part#>)[,<...>]/")) self.options.add_option( "--config", help="amanda configuration") self.options.add_option( "--host", help="client host") self.options.add_option( "--disk", help="disk to back up") self.options.add_option( "--level", type="int", help="dump level") self.options.add_option( "--execute_where", "--execute-where", help="where this script is executed") (self.params, self.args) = self.options.parse_args() # link params into this object for convenience for p in self.all_params: try: setattr(self,p,getattr(self.params,p,None)) except AttributeError: # can't set 'debug' attribute; it's a property defined below pass def check_args(self): if len(self.args) != 1: self.options.error("must have exactly one arg; found %d" % len(self.args)) def check_required_params(self): for param in self.required_params: if not getattr(self.params, param): self.options.error("Required parameter '%s' missing" % param) def check_device_param(self): if not self.device.startswith( self.params.mount_base + "/"): self.options.error("device path must begin with " "the base mount directory") def print_params(self): self.util.infomsg("\nCommand line argument parsing results:") for p in self.interesting_params: self.util.infomsg(" %25s: %s" % (p, getattr(self,p,None))) self.util.infomsg("\nScheme:") for layer in self.scheme: if len(layer) == 2: self.util.infomsg(" %-15s %s" % (layer[0], layer[1])) else: self.util.infomsg(" %s" % layer[0]) self.util.infomsg("") @property def debug(self): return self.params.debug == 1 @property def scheme(self): target_string = self.params.device[ len(self.params.mount_base)+1:] # e.g. [['lvm', 'vg+lv'], ['raid1'], ['part', '1']] # (param values like for lvm are split within the params' respective # handling code) scheme = [i.split(self.layer_param_field_sep[1]) for i in target_string.split(self.layer_param_field_sep[0])] return scheme @property def field_sep(self): return self.layer_param_field_sep[2] @property def entry_point(self): return self.args[0].lower() @property def entry_point_split(self): return self.entry_point.split('-') @property def set_up_mode(self): return self.entry_point in self.set_up_entry_points @property def tear_down_mode(self): return self.entry_point in self.tear_down_entry_points @property def action(self): return self.entry_point_split[-1] @property def pre_post(self): return self.entry_point_split[1] @property def logfile(self): return self.params.snaplayers_log_pattern % \ { 'timestamp' : strftime("%Y%m%d%H%M%S", localtime()), 'disk' : self.params.disk, 'entry_point' : self.entry_point, }