[RFC] snapper interface for fs-snapshot plugin

Mathieu Chouquet-Stringer m+yum at thi.eu.com
Wed Dec 4 12:41:57 UTC 2013


	Hello,

As a user of btrfs, I've been using the fs-snapshot plugin for a while.
I discovered snapper (http://snapper.io/) a while ago now and started
looking at how it could be used with the fs-snapshot plugin. FYI snapper
is already available as a package in Fedora.

Reading the source, I see there are references to it, namely while
creating LVM snapshots (but it doesn't go further than that so it's
pretty much useless as it is).

To people who have never used snapper, the website lists the following
features:
- Manually create snapshots
- Automatically create snapshots, e.g. with YaST and zypp
- Automatically create timeline of snapshots
- Show and revert changes between snapshots
- Works with btrfs, ext4 and thin-provisioned LVM volumes
- Supports Access Control Lists and Extended Attributes
- Automatic cleanup of old snapshots
- Command line interface
- D-Bus interface
- PAM module to create snapshots during login and logout

An example of how it can be used: http://lizards.opensuse.org/2011/04/01/introducing-snapper/

To me the killer features are really regular snapshots and the fact you
can diff them...

I've created a quick and dirty patch for fs-snapshot which adds a
use_snapper option to the plugin. When enabled (it's disabled by
default), instead of using the native btrfs tool to create snaps, it
uses snapper (in pre and post).

Is this something people could be interested in? Could it be merged as
such (after some polishing) or should I rather target dnf?

Thanks for your feedback.

diff --git a/plugins/fs-snapshot/fs-snapshot.conf b/plugins/fs-snapshot/fs-snapshot.conf
index 9ada717..b253b17 100644
--- a/plugins/fs-snapshot/fs-snapshot.conf
+++ b/plugins/fs-snapshot/fs-snapshot.conf
@@ -1,6 +1,7 @@
 [main]
 enabled = 1
 create_snapshots_in_post = 0
+use_snapper = 0
 
 [lvm]
 enabled = 0
diff --git a/plugins/fs-snapshot/fs-snapshot.py b/plugins/fs-snapshot/fs-snapshot.py
index 786b0c1..95134d9 100644
--- a/plugins/fs-snapshot/fs-snapshot.py
+++ b/plugins/fs-snapshot/fs-snapshot.py
@@ -209,16 +209,31 @@ def _create_btrfs_snapshot(conduit, snapshot_tag, volume):
     if not mntpnt.endswith("/"):
         mntpnt = mntpnt + "/"
 
-    snapname = mntpnt + snapshot_tag
-    conduit.info(1, "fs-snapshot: snapshotting " + mntpnt + ": " + snapname)
-    p = Popen(["/sbin/btrfs", "filesystem", "sync", mntpnt], stdout=PIPE, stderr=PIPE)
-    err = p.wait()
-    if err:
-        return 1
-    p = Popen(["/sbin/btrfs", "subvolume", "snapshot", mntpnt, snapname], stdout=PIPE, stderr=PIPE)
-    err = p.wait()
-    if err:
-        return 1
+    if conduit._base.__plugin_fs_snapshot_use_snapper:
+	if not conduit._base.__plugin_fs_snapshot_pre_snapshot_tag:
+            conduit.info(1, "fs-snapshot: pre-snapshotting " + mntpnt)
+            p = Popen(["/usr/bin/snapper", "create", "--type=pre", "--cleanup-algorithm=number", "--print-number", "--description=yum"], stdout=PIPE, stderr=PIPE)
+            err = p.wait()
+            if err:
+	        return 1
+	    conduit._base.__plugin_fs_snapshot_pre_snapshot_tag = p.communicate()[0].rstrip()
+	else:
+            conduit.info(1, "fs-snapshot: post-snapshotting " + mntpnt)
+            p = Popen(["/usr/bin/snapper", "create", "--type=post", "--cleanup-algorithm=number", "--pre-number=" + conduit._base.__plugin_fs_snapshot_pre_snapshot_tag], stdout=PIPE, stderr=PIPE)
+            err = p.wait()
+            if err:
+	        return 1
+    else:
+        snapname = mntpnt + snapshot_tag
+        conduit.info(1, "fs-snapshot: snapshotting " + mntpnt + ": " + snapname)
+        p = Popen(["/sbin/btrfs", "filesystem", "sync", mntpnt], stdout=PIPE, stderr=PIPE)
+        err = p.wait()
+        if err:
+            return 1
+        p = Popen(["/sbin/btrfs", "subvolume", "snapshot", mntpnt, snapname], stdout=PIPE, stderr=PIPE)
+        err = p.wait()
+        if err:
+            return 1
     return 2
 
 def add_lvm_tag_to_snapshot(conduit, tag, snap_volume):
@@ -303,12 +318,15 @@ def create_snapshots(conduit):
     everything that is snapshottable, since we do not know what an RPM will
     modify (thank you scriptlets).
     """
-    # common snapshot tag format: yum_${year}${month}${day}${hour}${minute}${sec}
-    snapshot_tag = "yum_" + time.strftime("%Y%m%d%H%M%S")
-    if not conduit._base.__plugin_fs_snapshot_pre_snapshot_tag:
-        conduit._base.__plugin_fs_snapshot_pre_snapshot_tag = snapshot_tag
-    else:
-        conduit._base.__plugin_fs_snapshot_post_snapshot_tag = snapshot_tag
+    if conduit._base.__plugin_fs_snapshot_use_snapper:
+        snapshot_tag = None
+    else:
+        # common snapshot tag format: yum_${year}${month}${day}${hour}${minute}${sec}
+        snapshot_tag = "yum_" + time.strftime("%Y%m%d%H%M%S")
+        if not conduit._base.__plugin_fs_snapshot_pre_snapshot_tag:
+            conduit._base.__plugin_fs_snapshot_pre_snapshot_tag = snapshot_tag
+        else:
+            conduit._base.__plugin_fs_snapshot_post_snapshot_tag = snapshot_tag
 
     volumes = get_volumes(conduit)
     for volume in volumes:
@@ -320,11 +336,12 @@ def create_snapshots(conduit):
             conduit.registerPackageName("yum-plugin-fs-snapshot")
 
 def pretrans_hook(conduit):
+    conduit._base.__plugin_fs_snapshot_use_snapper = conduit.confBool('main', 'use_snapper', default=0)
     conduit._base.__plugin_fs_snapshot_pre_snapshot_tag = None
     conduit._base.__plugin_fs_snapshot_post_snapshot_tag = None
     create_snapshots(conduit)
 
 def posttrans_hook(conduit):
     create_snapshots_in_post = conduit.confBool('main', 'create_snapshots_in_post', default=0)
-    if create_snapshots_in_post:
+    if create_snapshots_in_post or conduit._base.__plugin_fs_snapshot_use_snapper:
         create_snapshots(conduit)

-- 
Mathieu Chouquet-Stringer                               m+yum at thi.eu.com
            The sun itself sees not till heaven clears.
	             -- William Shakespeare --


More information about the Yum-devel mailing list