pvl.backup-rsync: implement --sudo
authorTero Marttila <terom@paivola.fi>
Sat, 16 Feb 2013 21:42:10 +0200
changeset 70 3b1290aeed12
parent 69 468704db09c4
child 71 6f9f59b5c4c5
pvl.backup-rsync: implement --sudo
bin/pvl.backup-rsync
pvl/backup/rsync.py
--- a/bin/pvl.backup-rsync	Sat Feb 16 21:41:42 2013 +0200
+++ b/bin/pvl.backup-rsync	Sat Feb 16 21:42:10 2013 +0200
@@ -50,23 +50,26 @@
 
     #
     parser.add_option('-c', '--command',    metavar='CMD', default=os.environ.get('SSH_ORIGINAL_COMMAND'),
-            help="rsync command to execute")
+            help="Rsync command to execute")
 
     parser.add_option('-C', '--given-command', action='store_true', default=False,
-            help="use given command in `rsync -e '%prog -C --' ...` format")
+            help="Use given command in `rsync -e '%prog -C --' ...` format")
 
     parser.add_option('-n', '--noop', action='store_true', default=False,
             help="Parse command, but do not execute")
 
     parser.add_option('-R', '--readonly',   action='store_true', default=False,
-            help="restrict to read/source mode")
+            help="Restrict to read/source mode")
 
     parser.add_option('-P', '--restrict-path', metavar='PATH', action='append',
-            help="restrict to given path prefix")
+            help="Restrict to given path prefix")
 
     parser.add_option('--allow-remote',     action='store_true', default=False,
             help="Allow remote rsync sources")
 
+    parser.add_option('--sudo',             action='store_true',
+            help="Execute rsync under sudo")
+
     # lvm options
     parser.add_option('-L', '--snapshot-size', metavar='SIZE', default=lvm.LVM_SNAPSHOT_SIZE,
             help="create snapshot with given LV size (used to store writes during backup)")
@@ -130,6 +133,7 @@
                 restrict_paths      = options.restrict_path,
                 allow_remote        = options.allow_remote,
                 lvm_opts            = dict(
+                    sudo    = options.sudo,
                     size    = options.snapshot_size, 
                     wait    = options.snapshot_wait,
                     retry   = options.snapshot_retry,
@@ -148,7 +152,9 @@
     # execute
     try :
         # run rsync within the source (may perform additional stuff like snapshot...)
-        source.execute(rsync_options, srcdst)
+        source.execute(rsync_options, srcdst,
+                sudo        = options.sudo,
+        )
 
     except InvokeError, e:
         log.error("%s failed: %d", e.cmd, e.exit)
--- a/pvl/backup/rsync.py	Sat Feb 16 21:41:42 2013 +0200
+++ b/pvl/backup/rsync.py	Sat Feb 16 21:42:10 2013 +0200
@@ -14,7 +14,6 @@
 
 log = logging.getLogger('pvl.backup.rsync')
 
-# Path to rsync binary
 RSYNC = '/usr/bin/rsync'
 
 def rsync (source, dest, **opts) :
@@ -52,13 +51,15 @@
         rsync server-mode execution.
     """
 
-    def _execute (self, options, srcdst, path) :
+    def _execute (self, options, srcdst, path, sudo=False) :
         """
             Underlying rsync just reads from filesystem.
 
                 options     - list of rsync options
                 srcdst      - the (source, dest) pair with None placeholder, as returned by parse_command
                 path        - the real path to replace None with
+
+                sudo        - execute rsync using sudo
         """
     
         # one of this will be None
@@ -69,10 +70,10 @@
         dst = dst or path
 
         log.info("rsync %s %s %s", ' '.join(options), src, dst)
-        
+
         try :
-            # invoke directly, no option-handling, nor stdin/out redirection
-            invoke.invoke(RSYNC, options + [ src, dst ], data=False)
+            # invoke directly; no option-handling, nor stdin/out redirection
+            invoke.invoke(RSYNC, options + [ src, dst ], data=False, sudo=sudo)
 
         except invoke.InvokeError as ex :
             raise RsyncError(ex)
@@ -87,13 +88,13 @@
 
         self.path = path
 
-    def execute (self, options, srcdst) :
+    def execute (self, options, srcdst, **opts) :
         """
                 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)
+        return self._execute(options, srcdst, self.path, **opts)
 
     def __str__ (self) :
         return self.path
@@ -114,13 +115,13 @@
         # glue
         self.path = host + ':' + path
 
-    def execute (self, options, srcdst) :
+    def execute (self, options, srcdst, **opts) :
         """
                 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)
+        return self._execute(options, srcdst, self.path, **opts)
 
     def __str__ (self) :
         return self.path
@@ -130,18 +131,21 @@
         Backup LVM LV by snapshotting + mounting it.
     """
 
-    def __init__ (self, volume, **opts) :
+    def __init__ (self, vg, lv, sudo=None, **opts) :
         """
-            volume      - the LVMVolume to snapshot
             **opts      - options for LVM.snapshot
         """
 
         RSyncServer.__init__(self)
+        
+        # lvm
+        self.lvm = LVM(vg, sudo=sudo)
+        self.volume = self.lvm.volume(lv)
 
-        self.volume = volume
+        self.sudo = sudo
         self.snapshot_opts = opts
  
-    def execute (self, options, srcdst) :
+    def execute (self, options, srcdst, sudo=False, **opts) :
         """
             Snapshot, mount, execute
 
@@ -161,12 +165,12 @@
             # mount
             log.info("Mounting snapshot: %s", snapshot)
 
-            with mount(snapshot.dev_path, name_hint=('lvm_' + snapshot.name + '_'), readonly=True) as mountpoint:
+            with mount(snapshot.dev_path, name_hint=('lvm_' + snapshot.name + '_'), readonly=True, sudo=sudo) as mountpoint:
                 # rsync!
                 log.info("Running rsync: %s", mountpoint)
 
                 # with trailing slash
-                return self._execute(options, srcdst, mountpoint.path + '/')
+                return self._execute(options, srcdst, mountpoint.path + '/', sudo=sudo, **opts)
 
             # cleanup
         # cleanup
@@ -322,10 +326,7 @@
         log.debug("LVM: %s/%s", vg, lv)
 
         # open
-        lvm = LVM(vg)
-        volume = lvm.volume(lv)
-
-        return RSyncLVMServer(volume, **lvm_opts)
+        return RSyncLVMServer(vg, lv, **lvm_opts)
 
     elif ':' in path and allow_remote :
         host, path = path.split(':', 1)