# HG changeset patch # User Tero Marttila # Date 1340094758 -10800 # Node ID 462cecaa70d0fa5bbe2f05d6241371de2a5a2727 # Parent 0de61433a42fced21bbdb36a6320741acfb5f044 pvl.backup-snapshot: handle target snapshot/rsync errors diff -r 0de61433a42f -r 462cecaa70d0 bin/pvl.backup-snapshot --- a/bin/pvl.backup-snapshot Tue Jun 19 11:30:59 2012 +0300 +++ b/bin/pvl.backup-snapshot Tue Jun 19 11:32:38 2012 +0300 @@ -296,6 +296,13 @@ def __str__ (self) : return self.name +class SnapshotError (Exception) : + """ + An error handling Target.snapshot() + """ + + pass + class Target (object) : """ A target run, i.e. a rsync-snapshot destination dir @@ -412,6 +419,8 @@ def snapshot (self, options, now) : """ Perform the rsync from our source to self.snapshot_dir. + + Raises rsync.RsyncError or SnapshotError. """ # new snapshot @@ -420,7 +429,7 @@ temp_path = os.path.join(self.snapshots_dir, 'tmp') if os.path.exists(temp_path) : - raise Exception("Old temp snapshot dir remains, please clean up: {path}".format(path=temp_path)) + raise SnapshotError("Old temp snapshot dir remains, please clean up: {path}".format(path=temp_path)) # link-dest from current? if os.path.exists(self.current_path) : @@ -449,14 +458,24 @@ # to tempdir log.debug("rsync %s -> %s", self.source, temp_path) - # 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)) + try : + # 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) - os.rename(temp_path, snapshot_path) + except rsync.RsyncError as ex : + # XXX: leaves temp_path in place, which must be removed or cleaned up.. + # maybe use {snapshot_name}.tmp instead? + log.warn("%s: rsync failed:", self, exc_info=ex) - return snapshot_name + # run() handles this + raise + + else : + # move in to final name + log.debug("rename %s -> %s", temp_path, snapshot_path) + os.rename(temp_path, snapshot_path) + + return snapshot_name def interval (self, options, interval, now, snapshot_name) : """ @@ -618,6 +637,7 @@ """ # initial rsync + # may fail with RsyncError snapshot_name = self.snapshot(options, now) # update current @@ -675,15 +695,28 @@ now = datetime.datetime.now() log.debug("%s: started snapshot run at: %s", self, now) + + try : + # snapshot + current + snapshot_name = self.run_snapshot(options, now) - # snapshot + current - snapshot_name = self.run_snapshot(options, now) + except rsync.RsyncError as ex : + # failed, don't update run intervals or such + log.error("%s: snapshot rsync failed: %s", self, ex) + + return 1 + + except SnapshotError as ex : + # misc. failure + log.error("%s: %s", self, ex) + + return 2 # intervals? self.run_intervals(options, now, snapshot_name) # ok - return 1 + return 0 def __str__ (self) : return self.name