Blame SOURCES/BZ-1047793-lvm-snapshot.patch

d2a170
commit 13bbacb4dd25b83cd29389e0608fde1614537257
d2a170
Author: Valentina Mukhamedzhanova <vmukhame@redhat.com>
d2a170
Date:   Mon Jan 12 15:21:46 2015 +0100
d2a170
d2a170
     Multiple lvm fixes. BZ 1047793, BZ 1145485
d2a170
    - add fssnap_abort_on_errors config option
d2a170
    - fix default for fssnap_automatic_keep in the man page
d2a170
    - add logging for automatic fssnap events
d2a170
    - add lvm binary path test to _FSSnap.available
d2a170
    - check for lvm2 and lvm2-python-libs packages instead of python-lvm
d2a170
d2a170
diff --git a/docs/yum.8 b/docs/yum.8
d2a170
index 998a5ad..a0038f6 100644
d2a170
--- a/docs/yum.8
d2a170
+++ b/docs/yum.8
d2a170
@@ -741,7 +741,7 @@ then you can create and delete snapshots using:
d2a170
 .br 
d2a170
 
d2a170
 .br
d2a170
-Configuration Options: \fBfssnap_automatic_pre\fP, \fBfssnap_automatic_post\fP, \fBfssnap_automatic_keep\fP, \fBfssnap_percentage\fP, \fBfssnap_devices\fP
d2a170
+Configuration Options: \fBfssnap_automatic_pre\fP, \fBfssnap_automatic_post\fP, \fBfssnap_automatic_keep\fP, \fBfssnap_percentage\fP, \fBfssnap_devices\fP, \fBfssnap_abort_on_errors\fP
d2a170
 
d2a170
 .IP
d2a170
 .IP "\fBfs\fP"
d2a170
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
d2a170
index 0362e85..272e07b 100644
d2a170
--- a/docs/yum.conf.5
d2a170
+++ b/docs/yum.conf.5
d2a170
@@ -873,7 +873,7 @@ Boolean (1, 0, True, False, yes, no) Defaults to False
d2a170
 .IP
d2a170
 \fBfssnap_automatic_keep\fR
d2a170
 How many old snapshots should yum keep when trying to automatically create a 
d2a170
-new snapshot. Setting to 0 disables this feature. Default is '0'.
d2a170
+new snapshot. Setting to 0 disables this feature. Default is '1'.
d2a170
 
d2a170
 .IP
d2a170
 \fBfssnap_automatic_percentage\fR
d2a170
@@ -887,6 +887,21 @@ first match (positive or negative) wins.
d2a170
 Default is: !*/swap !*/lv_swap glob:/etc/yum/fssnap.d/*.conf
d2a170
 
d2a170
 .IP
d2a170
+\fBfssnap_abort_on_errors\fR
d2a170
+When fssnap_automatic_pre or fssnap_automatic_post is enabled, it's possible to specify which
d2a170
+fssnap errors should make the transaction fail. The default is `any'.
d2a170
+
d2a170
+`broken-setup' - Abort current transaction if snapshot support is unavailable because
d2a170
+lvm is missing or broken.
d2a170
+
d2a170
+`snapshot-failure' - Abort current transaction if creating a snapshot fails (e.g. there is not enough
d2a170
+free space to make a snapshot).
d2a170
+
d2a170
+`any' - Abort current transaction if any of the above occurs.
d2a170
+
d2a170
+`none' - Never abort a transaction in case of errors.
d2a170
+
d2a170
+.IP
d2a170
 \fBdepsolve_loop_limit\fR
d2a170
 Set the number of times any attempt to depsolve before we just give up. This
d2a170
 shouldn't be needed as yum should always solve or fail, however it has been
d2a170
diff --git a/yum/__init__.py b/yum/__init__.py
d2a170
index 6d2c078..347aa7c 100644
d2a170
--- a/yum/__init__.py
d2a170
+++ b/yum/__init__.py
d2a170
@@ -1727,6 +1727,13 @@ much more problems).
d2a170
         :raises: :class:`yum.Errors.YumRPMTransError` if there is a
d2a170
            transaction cannot be completed
d2a170
         """
d2a170
+        if (self.conf.fssnap_automatic_pre or self.conf.fssnap_automatic_post) and not self.fssnap.available:
d2a170
+            msg = _("Snapshot support not available.")
d2a170
+            if self.conf.fssnap_abort_on_errors in ('broken-setup', 'any'):
d2a170
+                raise Errors.YumRPMTransError(msg="Aborting transaction.", errors=msg)
d2a170
+            else:
d2a170
+                self.verbose_logger.critical(msg)
d2a170
+
d2a170
         if self.fssnap.available and ((self.conf.fssnap_automatic_pre or
d2a170
                                        self.conf.fssnap_automatic_post) and
d2a170
                                       self.conf.fssnap_automatic_keep):
d2a170
@@ -1748,17 +1755,30 @@ much more problems).
d2a170
                 if num > self.conf.fssnap_automatic_keep:
d2a170
                     todel.append(snap['dev'])
d2a170
             # Display something to the user?
d2a170
-            self.fssnap.del_snapshots(devices=todel)
d2a170
+            snaps = self.fssnap.del_snapshots(devices=todel)
d2a170
+            if len(snaps):
d2a170
+                self.verbose_logger.info(_("Deleted %u snapshots.") % len(snaps))
d2a170
 
d2a170
         if (self.fssnap.available and
d2a170
             (not self.ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST) and
d2a170
             self.conf.fssnap_automatic_pre)):
d2a170
             if not self.fssnap.has_space(self.conf.fssnap_percentage):
d2a170
-                msg = _("Not enough space to create pre. FS snapshot, aborting transaction.")
d2a170
-                raise Errors.YumRPMTransError(msg=msg, errors=[])
d2a170
+                msg = _("Not enough space to create pre. FS snapshot.")
d2a170
+                if self.conf.fssnap_abort_on_errors in ('snapshot-failure', 'any'):
d2a170
+                    raise Errors.YumRPMTransError(msg="Aborting transaction", errors=msg)
d2a170
+                else:
d2a170
+                    self.verbose_logger.critical(msg)
d2a170
             else:
d2a170
                 tags = {'*': ['reason=automatic']} # FIXME: pre. tags
d2a170
-                self.fssnap.snapshot(self.conf.fssnap_percentage, tags=tags)
d2a170
+                snaps = self.fssnap.snapshot(self.conf.fssnap_percentage, tags=tags)
d2a170
+                if not snaps:
d2a170
+                    msg = _("Failed to create snapshot")
d2a170
+                    if self.conf.fssnap_abort_on_errors in ('snapshot-failure', 'any'):
d2a170
+                        raise Errors.YumRPMTransError(msg="Aborting transaction", errors=msg)
d2a170
+                    else:
d2a170
+                        self.verbose_logger.critical(msg)
d2a170
+                for (odev, ndev) in snaps:
d2a170
+                    self.verbose_logger.info(_("Created snapshot from %s, results is: %s") % (odev, ndev))
d2a170
 
d2a170
         self.plugins.run('pretrans')
d2a170
 
d2a170
@@ -1895,11 +1915,14 @@ much more problems).
d2a170
             self.conf.fssnap_automatic_post)):
d2a170
             if not self.fssnap.has_space(self.conf.fssnap_percentage):
d2a170
                 msg = _("Not enough space to create post trans FS snapshot.")
d2a170
-                self.logger.critical(msg)
d2a170
+                self.verbose_logger.critical(msg)
d2a170
             else:
d2a170
                 tags = {'*': ['reason=automatic']} # FIXME: post tags
d2a170
-                self.fssnap.snapshot(self.conf.fssnap_percentage, tags=tags)
d2a170
-
d2a170
+                snaps = self.fssnap.snapshot(self.conf.fssnap_percentage, tags=tags)
d2a170
+                if not snaps:
d2a170
+                    self.verbose_logger.critical(_("Failed to create snapshot"))
d2a170
+                for (odev, ndev) in snaps:
d2a170
+                    self.verbose_logger.info(_("Created snapshot from %s, results is: %s") % (odev, ndev))
d2a170
         return resultobject
d2a170
 
d2a170
     def verifyTransaction(self, resultobject=None, txmbr_cb=None):
d2a170
diff --git a/yum/config.py b/yum/config.py
d2a170
index 8eab5bc..02061ba 100644
d2a170
--- a/yum/config.py
d2a170
+++ b/yum/config.py
d2a170
@@ -899,6 +899,7 @@ class YumConf(StartupConf):
d2a170
     fssnap_devices = ListOption("!*/swap !*/lv_swap "
d2a170
                                 "glob:/etc/yum/fssnap.d/*.conf",
d2a170
                                 parse_default=True)
d2a170
+    fssnap_abort_on_errors = SelectionOption('any', ('broken-setup', 'snapshot-failure', 'any', 'none'))
d2a170
 
d2a170
     depsolve_loop_limit = PositiveIntOption(100, names_of_0=["<forever>"])
d2a170
 
d2a170
diff --git a/yum/fssnapshots.py b/yum/fssnapshots.py
d2a170
index e912ea1..9af252d 100755
d2a170
--- a/yum/fssnapshots.py
d2a170
+++ b/yum/fssnapshots.py
d2a170
@@ -146,7 +143,8 @@ class _FSSnap(object):
d2a170
             devices = []
d2a170
 
d2a170
         self.version = _ver
d2a170
-        self.available = bool(lvm)
d2a170
+        # Parts of the API seem to work even when lvm is not actually installed, hence the path test
d2a170
+        self.available = bool(lvm and os.path.exists("/sbin/lvm"))
d2a170
         self.postfix_static = "_yum_"
d2a170
         self._postfix = None
d2a170
         self._root = root
d2a170
diff --git a/yumcommands.py b/yumcommands.py
d2a170
index a18bc5c..e77d209 100644
d2a170
--- a/yumcommands.py
d2a170
+++ b/yumcommands.py
d2a170
@@ -4264,11 +4264,13 @@ class FSSnapshotCommand(YumCommand):
d2a170
             subcommand = 'summary'
d2a170
 
d2a170
         if not base.fssnap.available:
d2a170
-            if not base.rpmdb.searchNames(['python-lvm']):
d2a170
-                print _("Snapshot support not available, no python-lvm package installed.")
d2a170
-            else:
d2a170
-                print _("Snapshot support not available, python-lvm is old/broken.")
d2a170
-            return 0, [basecmd + ' ' + subcommand + ' done']
d2a170
+            msg = _("Snapshot support not available, please check your lvm installation.")
d2a170
+            if not base.rpmdb.searchNames(['lvm2']):
d2a170
+                msg += " " + _("No lvm2 package installed.")
d2a170
+            if not base.rpmdb.searchNames(['lvm2-python-libs']):
d2a170
+                msg += " " + _("No lvm2-python-libs package installed.")
d2a170
+            print msg
d2a170
+            return 1, [basecmd + ' ' + subcommand + ' done']
d2a170
 
d2a170
         if subcommand == 'list':
d2a170
             snaps = base.fssnap.old_snapshots()
d2a170
@@ -4301,10 +4303,11 @@ class FSSnapshotCommand(YumCommand):
d2a170
         if subcommand == 'create':
d2a170
             tags = {'*': ['reason=manual']}
d2a170
             pc = base.conf.fssnap_percentage
d2a170
-            for (odev, ndev) in base.fssnap.snapshot(pc, tags=tags):
d2a170
-                print _("Created snapshot from %s, results is: %s") %(odev,ndev)
d2a170
-            else:
d2a170
+            snaps = base.fssnap.snapshot(pc, tags=tags)
d2a170
+            if not snaps:
d2a170
                 print _("Failed to create snapshots")
d2a170
+            for (odev, ndev) in snaps:
d2a170
+                print _("Created snapshot from %s, results is: %s") %(odev,ndev)
d2a170
 
d2a170
         if subcommand == 'summary':
d2a170
             snaps = base.fssnap.old_snapshots()
d2a170
commit 29440b1175411c3ccaca6010df8dec2d96088fbd
d2a170
Author: Valentina Mukhamedzhanova <vmukhame@redhat.com>
d2a170
Date:   Thu Jul 9 15:26:29 2015 +0200
d2a170
d2a170
    Stop caching fssnapshot postfixes and add microseconds
d2a170
d2a170
diff --git a/yum/fssnapshots.py b/yum/fssnapshots.py
d2a170
index a07271d..10ec012 100755
d2a170
--- a/yum/fssnapshots.py
d2a170
+++ b/yum/fssnapshots.py
d2a170
@@ -3,6 +3,7 @@
d2a170
 import os
d2a170
 import fnmatch
d2a170
 import time
d2a170
+from datetime import datetime
d2a170
 
d2a170
 import subprocess
d2a170
 
d2a170
@@ -228,23 +229,13 @@ class _FSSnap(object):
d2a170
 
d2a170
         return ret
d2a170
 
d2a170
-    def _get_postfix(self):
d2a170
-        if self._postfix is None:
d2a170
-            self._postfix = self.postfix_static
d2a170
-            self._postfix += time.strftime("%Y%m%d%H%M%S")
d2a170
-        return self._postfix
d2a170
-
d2a170
-    postfix = property(fget=lambda self: self._get_postfix(),
d2a170
-                       fset=lambda self, value: setattr(self, "_postfix",value),
d2a170
-                       fdel=lambda self: setattr(self, "_postfix", None),
d2a170
-                       doc="postfix for snapshots")
d2a170
 
d2a170
     def snapshot(self, percentage=100, prefix='', postfix=None, tags={}):
d2a170
         """ Attempt to take a snapshot, note that errors can happen after
d2a170
             this function succeeds. """
d2a170
 
d2a170
         if postfix is None:
d2a170
-            postfix = self.postfix
d2a170
+            postfix = '%s%s' % (self.postfix_static, datetime.now().strftime("%Y%m%d%H%M%S.%f"))
d2a170
 
d2a170
         ret = []
d2a170
         for vgname in self._vgnames:
d2a170
commit 2678b0a2eb042e011bcafb507eae5ea3565c9110
d2a170
Author: Valentina Mukhamedzhanova <vmukhame@redhat.com>
d2a170
Date:   Mon Jul 13 16:28:32 2015 +0200
d2a170
d2a170
    Test for lvm binary before using.
d2a170
d2a170
diff --git a/yum/fssnapshots.py b/yum/fssnapshots.py
d2a170
index 10ec012..70f80a0 100755
d2a170
--- a/yum/fssnapshots.py
d2a170
+++ b/yum/fssnapshots.py
d2a170
@@ -155,7 +155,7 @@ class _FSSnap(object):
d2a170
         if not self._devs:
d2a170
             return
d2a170
 
d2a170
-        self._vgnames = _list_vg_names()
d2a170
+        self._vgnames = _list_vg_names() if self.available else []
d2a170
 
d2a170
     def _use_dev(self, vgname, lv=None):
d2a170
 
d2a170
commit e756473a1b01f40f087488f72d002d9993843a84
d2a170
Author: Valentina Mukhamedzhanova <vmukhame@redhat.com>
d2a170
Date:   Wed Aug 12 12:54:55 2015 +0200
d2a170
d2a170
    Update not enough space messages for fssnapshot
d2a170
d2a170
diff --git a/yum/__init__.py b/yum/__init__.py
d2a170
index 48956e9..84bea3e 100644
d2a170
--- a/yum/__init__.py
d2a170
+++ b/yum/__init__.py
d2a170
@@ -1773,7 +1773,7 @@ much more problems).
d2a170
             (not self.ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST) and
d2a170
             self.conf.fssnap_automatic_pre)):
d2a170
             if not self.fssnap.has_space(self.conf.fssnap_percentage):
d2a170
-                msg = _("Not enough space to create pre. FS snapshot.")
d2a170
+                msg = _("Not enough space on logical volumes to create pre. FS snapshot.")
d2a170
                 if self.conf.fssnap_abort_on_errors in ('snapshot-failure', 'any'):
d2a170
                     raise Errors.YumRPMTransError(msg="Aborting transaction", errors=msg)
d2a170
                 else:
d2a170
@@ -1926,7 +1926,7 @@ much more problems).
d2a170
             (not self.ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST) and
d2a170
             self.conf.fssnap_automatic_post)):
d2a170
             if not self.fssnap.has_space(self.conf.fssnap_percentage):
d2a170
-                msg = _("Not enough space to create post trans FS snapshot.")
d2a170
+                msg = _("Not enough space on logical volumes to create post trans FS snapshot.")
d2a170
                 self.verbose_logger.critical(msg)
d2a170
             else:
d2a170
                 tags = {'*': ['reason=automatic']} # FIXME: post tags
d2a170
diff --git a/yumcommands.py b/yumcommands.py
d2a170
index 4a39ddb..5234260 100644
d2a170
--- a/yumcommands.py
d2a170
+++ b/yumcommands.py
d2a170
@@ -4311,7 +4311,7 @@ class FSSnapshotCommand(YumCommand):
d2a170
             if base.fssnap.has_space(pc):
d2a170
                 print _("Space available to take a snapshot.")
d2a170
             else:
d2a170
-                print _("Not enough space available to take a snapshot.")
d2a170
+                print _("Not enough space available on logical volumes to take a snapshot.")
d2a170
 
d2a170
         if subcommand == 'create':
d2a170
             tags = {'*': ['reason=manual']}