diff --git a/zfs_autobackup/ZfsAuto.py b/zfs_autobackup/ZfsAuto.py index 39c8a19..4027fcb 100644 --- a/zfs_autobackup/ZfsAuto.py +++ b/zfs_autobackup/ZfsAuto.py @@ -1,4 +1,5 @@ import argparse +import re import sys from .CliBase import CliBase @@ -112,6 +113,14 @@ def get_parser(self): help=argparse.SUPPRESS) + def regex_argument_type(input_line): + """Parses regex arguments into re.Pattern objects""" + try: + return re.compile(input_line) + except: + raise ValueError("Could not parse argument '{}' as a regular expression".format(input_line)) + group.add_argument('--exclude-snapshot-pattern', action='append', default=[], type=regex_argument_type, help="Regular expression to match snapshots that will be ignored.") + return parser def print_error_sources(self): diff --git a/zfs_autobackup/ZfsAutobackup.py b/zfs_autobackup/ZfsAutobackup.py index 8addcd4..e3616ce 100644 --- a/zfs_autobackup/ZfsAutobackup.py +++ b/zfs_autobackup/ZfsAutobackup.py @@ -472,7 +472,8 @@ def run(self): snapshot_time_format=self.snapshot_time_format, hold_name=self.hold_name, logger=self, ssh_config=self.args.ssh_config, ssh_to=self.args.ssh_source, readonly=self.args.test, - debug_output=self.args.debug_output, description=description, thinner=source_thinner) + debug_output=self.args.debug_output, description=description, thinner=source_thinner, + exclude_snapshot_patterns=self.args.exclude_snapshot_pattern) ################# select source datasets self.set_title("Selecting") diff --git a/zfs_autobackup/ZfsAutoverify.py b/zfs_autobackup/ZfsAutoverify.py index f8c27ae..96abd94 100644 --- a/zfs_autobackup/ZfsAutoverify.py +++ b/zfs_autobackup/ZfsAutoverify.py @@ -235,7 +235,8 @@ def run(self): snapshot_time_format=self.snapshot_time_format, hold_name=self.hold_name, logger=self, ssh_config=self.args.ssh_config, ssh_to=self.args.ssh_source, readonly=self.args.test, - debug_output=self.args.debug_output, description=description) + debug_output=self.args.debug_output, description=description, + exclude_snapshot_patterns=self.args.exclude_snapshot_pattern) ################# select source datasets self.set_title("Selecting") diff --git a/zfs_autobackup/ZfsDataset.py b/zfs_autobackup/ZfsDataset.py index 985afee..a8e83d4 100644 --- a/zfs_autobackup/ZfsDataset.py +++ b/zfs_autobackup/ZfsDataset.py @@ -124,6 +124,20 @@ def snapshot_name(self): def is_snapshot(self): """true if this dataset is a snapshot""" return self.name.find("@") != -1 + + @property + def is_excluded(self): + """true if this dataset is a snapshot and matches the exclude pattern""" + if not self.is_snapshot: + return False + + + for pattern in self.zfs_node.exclude_snapshot_patterns: + if pattern.search(self.name) is not None: + self.debug("Excluded (path matches snapshot exclude pattern)") + return True + + def is_selected(self, value, source, inherited, exclude_received, exclude_paths, exclude_unchanged): """determine if dataset should be selected for backup (called from @@ -1171,7 +1185,7 @@ def sync_snapshots(self, target_dataset, features, show_progress, filter_propert target_snapshot = target_dataset.find_snapshot(source_snapshot) # still virtual # does target actually want it? - if target_snapshot not in target_obsoletes: + if target_snapshot not in target_obsoletes and not source_snapshot.is_excluded: # do the rollback, one time at first transfer if do_rollback: diff --git a/zfs_autobackup/ZfsNode.py b/zfs_autobackup/ZfsNode.py index 982b20f..9f3fa5e 100644 --- a/zfs_autobackup/ZfsNode.py +++ b/zfs_autobackup/ZfsNode.py @@ -20,7 +20,7 @@ class ZfsNode(ExecuteNode): def __init__(self, logger, utc=False, snapshot_time_format="", hold_name="", ssh_config=None, ssh_to=None, readonly=False, description="", - debug_output=False, thinner=None): + debug_output=False, thinner=None, exclude_snapshot_patterns=[]): self.utc = utc self.snapshot_time_format = snapshot_time_format @@ -30,6 +30,8 @@ def __init__(self, logger, utc=False, snapshot_time_format="", hold_name="", ssh self.logger = logger + self.exclude_snapshot_patterns = exclude_snapshot_patterns + if ssh_config: self.verbose("Using custom SSH config: {}".format(ssh_config))