pvlbackup-rsync-snapshot: use pvl.backup.rsync.parse_source for sources, to support local LVM snapshots; also implement lvm-options section for target
--- a/bin/pvlbackup-rsync-snapshot Sun Apr 22 12:56:53 2012 +0300
+++ b/bin/pvlbackup-rsync-snapshot Sun Apr 22 13:16:10 2012 +0300
@@ -11,7 +11,7 @@
"""
from pvl.backup import __version__
-from pvl.backup import rsync
+from pvl.backup import rsync, invoke
import optparse, ConfigParser
import os, os.path, stat
@@ -314,6 +314,12 @@
# parse
yield Interval.from_target_config(interval, base, arg)
+ # type() mapping for lvm_options
+ LVM_OPTIONS = dict(
+ wait = float,
+ size = str,
+ )
+
@classmethod
def from_config (cls, options, name,
path = False,
@@ -324,10 +330,20 @@
# subsections
intervals = None,
rsync_options = None,
+ lvm_options = {},
) :
if not source and source is not False :
raise ConfigError("Missing required option: source for [target/{name}]".format(name=name))
+ # process lvm opts by LVM_OPTIONS types
+ lvm_options = dict((opt, cls.LVM_OPTIONS[opt](value)) for opt, value in lvm_options.iteritems())
+
+ # parse source -> rsync.RSyncServer
+ source_path = source
+ source = rsync.parse_source(source, lvm_opts=lvm_options)
+
+ log.info("parse source: %r -> %s", source_path, source)
+
# global defaults
_rsync_options = dict(options.rsync_options)
@@ -422,9 +438,10 @@
# rsync links absolute paths..
opts['link-dest'] = target_abs
- # go
log.debug("rsync %s -> %s", self.source, temp_path)
- rsync.rsync(self.source, temp_path, **opts)
+
+ # run the rsync.RSyncServer; None as a placeholder will get replaced with the actual source
+ self.source.execute(invoke.optargs(**opts), srcdst=(None, temp_path))
# move in to final name
log.debug("rename %s -> %s", temp_path, snapshot_path)
--- a/pvl/backup/rsync.py Sun Apr 22 12:56:53 2012 +0300
+++ b/pvl/backup/rsync.py Sun Apr 22 13:16:10 2012 +0300
@@ -75,6 +75,36 @@
return self._execute(options, srcdst, self.path)
+ def __str__ (self) :
+ return self.path
+
+class RSyncRemoteServer (RSyncServer) :
+ """
+ Remote filesystem backup.
+ """
+
+ def __init__ (self, host, path) :
+ """
+ host - remote SSH host
+ path - remote path
+ """
+
+ RSyncServer.__init__(self)
+
+ # glue
+ self.path = path + ':' + path
+
+ def execute (self, options, srcdst) :
+ """
+ options - list of rsync options
+ srcdst - the (source, dest) pair with None placeholder, as returned by parse_command
+ """
+
+ return self._execute(options, srcdst, self.path)
+
+ def __str__ (self) :
+ return self.path
+
class RSyncLVMServer (RSyncServer) :
"""
Backup LVM LV by snapshotting + mounting it.
@@ -121,6 +151,9 @@
# cleanup
# cleanup
+ def __str__ (self) :
+ return 'lvm:{volume}'.format(volume=self.volume)
+
def parse_command (command_parts, restrict_server=True, restrict_readonly=True) :
"""
Parse given rsync server command into bits.
@@ -246,6 +279,14 @@
volume = lvm.volume(lv)
return RSyncLVMServer(volume, **lvm_opts)
+
+ elif ':/' in path :
+ host, path = path.split(':', 1)
+
+ # remote host
+ log.info("remote: %s:%s", host, path)
+
+ return RSyncRemoteServer(host, path)
else :
# invalid
--- a/rsync-snapshot.conf Sun Apr 22 12:56:53 2012 +0300
+++ b/rsync-snapshot.conf Sun Apr 22 13:16:10 2012 +0300
@@ -44,11 +44,17 @@
# test-lvm
[targets/test-lvm]
path = ./test-lvm
-source = backups_test:lvm:asdf:test
+source = lvm:asdf:test
[targets/test-lvm/intervals]
recent = 4
+[targets/test-lvm/lvm-options]
+wait = 1
+size = 1G
+
+
+
## Runs
[run/twice-daily]
test = true