Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Issue #245 Snapshot exclude patterns #264

Merged
merged 1 commit into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions zfs_autobackup/ZfsAuto.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import re
import sys

from .CliBase import CliBase
Expand Down Expand Up @@ -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):
Expand Down
3 changes: 2 additions & 1 deletion zfs_autobackup/ZfsAutobackup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
3 changes: 2 additions & 1 deletion zfs_autobackup/ZfsAutoverify.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
16 changes: 15 additions & 1 deletion zfs_autobackup/ZfsDataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion zfs_autobackup/ZfsNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))

Expand Down
Loading