From 5d95fb20bd1410838f296e66e4ee5025284e1663 Mon Sep 17 00:00:00 2001 From: Tim Foster Date: Fri, 22 Aug 2008 13:59:25 +0100 Subject: [PATCH] Add RBAC support and a Changelog --- Changelog | 81 ++++++++++++++++++ README.zfs-auto-snapshot.txt | 13 +-- src/i.manifest | 76 +++++++++++++++++ src/lib/svc/method/zfs-auto-snapshot | 28 +++++-- src/postinstall | 58 ++++++++++++- src/r.manifest | 83 +++++++++++++++++++ .../system/filesystem/auto-snapshot-daily.xml | 12 ++- .../filesystem/auto-snapshot-frequent.xml | 30 ++++--- .../filesystem/auto-snapshot-hourly.xml | 26 ++++-- .../filesystem/auto-snapshot-monthly.xml | 26 ++++-- .../filesystem/auto-snapshot-weekly.xml | 26 ++++-- .../system/filesystem/zfs-auto-snapshot.xml | 36 +++++--- 12 files changed, 428 insertions(+), 67 deletions(-) create mode 100644 Changelog create mode 100755 src/i.manifest create mode 100755 src/r.manifest diff --git a/Changelog b/Changelog new file mode 100644 index 0000000..b28c348 --- /dev/null +++ b/Changelog @@ -0,0 +1,81 @@ +0.11 + +* Add RBAC support + - the service now runs under a zfssnap role + - service start/stop logs stay under /var/svc/log + - other logs saved to /export/home/zfssnap (and syslog) +* Add a 'zfs/interval' property value 'none' which doesn't use cron +* Add a 'zfs/fs-name' property value '##' +* Add a cache of svcprops to the method script +* Add a com.sun:auto-snapshot user property, com.sun:auto-snapshot:$LABEL + takes precedence +* Remove the seconds field of the snapshot name - we don't really need it +* Make recursive snapshots the default for bundled '//' manifests +* Changed the way // works with recursive snapshots + (look for local props only when using -r) +* Set avoidscrub to false by default (bug was fixed in in nv_94) +* Bugfix from Dan - Volumes are datasets too +* Automatically snapshot everything by setting com.sun:auto-snapshot=true + on startup. (this gets done on all root pools - existing properties set + to false will override this) +* Check for missed snapshots on startup +* Clean up shell style +* Clean up preremove script +* Write this Changelog + +0.10 + +* Bugfix from Reid Spencer - Tim can't spell "RECURSIVE" (hah, I can now!:-) +* Bugfix from Breandan Dezendorf - Labelled snapshots not being destroyed correctly +* Ability to avoid taking snapshots when pool scrubs are in progress + +0.9 + +* SVR4 packaging (with ugly postinstall/preremove scripts) +* Add some canned instances for frequent,daily,hourly,weekly,monthly snapshots +* Add 'zfs/fs-name' '//' property value +* Change the timeout for the start/stop methods to infinity +* Allow power users to avoid having ':' in snapshot names via $SEP +* Add GUI utilities and some basic GNOME integration + +0.8 + +* Bugfix from Dick Davies - fencepost error in crontab entries +* Add locking around crontab updates +* Add zfs/verbose feature for more logging if you really need it + +0.7 + +* Bugfix from Bill Sommerfeld - make less logging noise +* Add logging to syslog + +0.6 + +* Option to take backups using zfs send after snapshots are taken +* Allow us to have multiple schedules per filesystem (add labels) +* Better fault handling - drop SMF instance to 'maintenance' if stuff goes wrong + +0.5 + +* Bugfix from Joe Little - recursive snapshots weren't respecting retention limits + +0.4 + +* Make zenity gui work on s10u2 +* Clean up the logic that the gui uses to name different instances + +0.3 + +* Add snapshot retention limits + +0.2 + +* Fix the gui to show a different string when changing the interval +* Fix a bug where seperate instances were removing each other's cron jobs + +0.1 + +* Take periodic snapshots using cron and SMF +* Snapshot children +* Add zenity gui to create SMF manifests + diff --git a/README.zfs-auto-snapshot.txt b/README.zfs-auto-snapshot.txt index 3845e97..28179b3 100644 --- a/README.zfs-auto-snapshot.txt +++ b/README.zfs-auto-snapshot.txt @@ -27,7 +27,7 @@ GUI is documented as part of the installation instructions below. INSTALLATION To install, as root, pkgadd TIMFauto-snapshot. This package now contains -several canned SMF instances which are enabled by default. These are: +several canned SMF instances. These are: online 1:17:43 svc:/system/filesystem/zfs/auto-snapshot:hourly online 1:17:46 svc:/system/filesystem/zfs/auto-snapshot:monthly @@ -149,10 +149,13 @@ you can now import the manifest for this instance, using the command : then issue the command : # svcadm enable svc:/system/filesystem/zfs/auto-snapshot:tank-root_filesystem -You can see what work will be done by checking your crontab. As of version -0.7, all logging from the service is done from the method script using -the print_log function, which uses logger(1) to send message to syslogd(1M) -at priority level "daemon.notice". + +The service is run by a restricted role "zfssnap", which is created when installing +the service. It has the "ZFS File System Administration" RBAC Profile, as well +as the solaris.smf.manage.zfs-auto-snapshot Authorization. In order to see what +the service is doing, you can view the SMF log files in /var/svc/log for each +service instance and syslog, with more detailed logging output being sent to +the log files in the zfssnap role's home directory. (/export/home/zfssnap, by default) SEE ALSO diff --git a/src/i.manifest b/src/i.manifest new file mode 100755 index 0000000..72ebfdd --- /dev/null +++ b/src/i.manifest @@ -0,0 +1,76 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# i.manifest - smf(5) service manifest install class action script +# + +repfile=$PKG_INSTALL_ROOT/etc/svc/repository.db +export repfile + +# +# If the repository does not yet exist, create it from the appropriate seed. If +# for some reason the seeds do not exist, svccfg(1M) will create the repository +# automatically. +# +if [ ! -f $repfile ]; then + if [ -n "$SUNW_PKG_INSTALL_ZONENAME" -a \ + "$SUNW_PKG_INSTALL_ZONENAME" != "global" ]; then + [ -f $PKG_INSTALL_ROOT/lib/svc/seed/nonglobal.db ] && \ + /usr/bin/cp $PKG_INSTALL_ROOT/lib/svc/seed/nonglobal.db \ + $repfile + else + [ -f $PKG_INSTALL_ROOT/lib/svc/seed/global.db ] && \ + /usr/bin/cp $PKG_INSTALL_ROOT/lib/svc/seed/global.db \ + $repfile + fi + /usr/bin/chmod 0600 $repfile + /usr/bin/chown root:sys $repfile +fi + +if [ ! -r $PKG_INSTALL_ROOT/etc/svc/volatile/repository_door ]; then + # + # smf(5) is not presently running for the destination environment. + # Since we presently cannot refresh without a running svc.startd(1M), we + # cannot consistently handle dependent placement. Defer to next boot. + # + while read src dst; do + /usr/bin/cp -p $src $dst + done +else + # + # Local package install. + # + while read src dst; do + /usr/bin/cp -p $src $dst + + [ "$PKG_INSTALL_ROOT" = "" -o "$PKG_INSTALL_ROOT" = "/" ] && \ + SVCCFG_CHECKHASH=1 /usr/sbin/svccfg import $dst + done +fi + +exit 0 diff --git a/src/lib/svc/method/zfs-auto-snapshot b/src/lib/svc/method/zfs-auto-snapshot index 5fa0404..d864ff5 100755 --- a/src/lib/svc/method/zfs-auto-snapshot +++ b/src/lib/svc/method/zfs-auto-snapshot @@ -52,6 +52,7 @@ result=$SMF_EXIT_OK +export PATH=/usr/sbin:/usr/bin:${PATH} # A prefix we use on all snapshot created by this script. # See the definition of $SNAPNAME in the take_snapshot() @@ -76,6 +77,9 @@ LOG="" # a null string in this variable says we don't. HAS_RECURSIVE=$(zfs snapshot 2>&1 | fgrep -e '-r') +# OpenSolaris has no pfksh, so for now, we need to pfexec +# all calls to zfs that require privileges +PFZFS="pfexec zfs" function get_pair { NAME=$1 @@ -95,7 +99,7 @@ SMF_PROPS="$(svcprop -t -p zfs -p restarter/logfile $1 |\ -e 's#zfs/backup-lock#zfs/backup_lock#g' \ -e 's#zfs/snapshot-children#zfs/snapshot_children#g' \ -e 's#zfs/backup-save-cmd#zfs/backup_save_cmd#g' \ - -e 's#zfs/##g' -e 's/$/,/g')" + -e 's#zfs/##g' -e 's#restarter/##g' -e 's/$/,/g')" IFS=, for line in $SMF_PROPS ; do IFS=' @@ -377,7 +381,13 @@ function take_snapshot { FMRI=$1 zfs_smf_props $FMRI - export LOG=$logfile + # When taking snapshots, because we're running as a role + # and can't redirect our output through SMF, we don't have + # permissions to log to /var/svc/log, so we instead log + # to the role's home directory. + LOG_BASE=$(basename $logfile) + export LOG="$HOME/$LOG_BASE" + typeset DATE=$(date +%F-%H${SEP}%M) typeset FILESYS="$fs_name" typeset KEEP=$keep @@ -466,20 +476,20 @@ function take_snapshot { for child in $(zfs list -r -H -o name -t filesystem,volume $fs) ; do destroy_older_snapshots $child $KEEP $LABEL print_note "Taking snapshot $child@$SNAPNAME" - zfs snapshot $child@$SNAPNAME + $PFZFS snapshot $child@$SNAPNAME check_failure $? "Unable to take snapshot $child@$SNAPNAME." done else destroy_older_snapshots $fs $KEEP $LABEL $HAS_RECURSIVE print_note "Taking recursive snapshot $fs@$SNAPNAME" - zfs snapshot -r $fs@$SNAPNAME + $PFZFS snapshot -r $fs@$SNAPNAME check_failure $? "Unable to take recursive snapshots of $fs@$SNAPNAME." fi else destroy_older_snapshots $fs $KEEP $LABEL print_note "Taking snapshot $fs@$SNAPNAME" - zfs snapshot $fs@$SNAPNAME + $PFZFS snapshot $fs@$SNAPNAME check_failure $? "Unable to take snapshot $fs@$SNAPNAME." fi @@ -532,7 +542,7 @@ function destroy_older_snapshots { # using print_note, as this checks our $VERBOSE flag print_note "$snapshot being destroyed ${RECURSIVE} as per \ retention policy." - zfs destroy ${RECURSIVE} $snapshot + $PFZFS destroy ${RECURSIVE} $snapshot check_failure $? "Unable to destroy $snapshot" "NON_FATAL" else # don't destroy this one @@ -697,12 +707,12 @@ function take_backup { # filesystem backup-type label fmri case $BACKUP in "incremental") print_note "Starting incr. ZFS send of differences between $PREV_SNAP and $LAST_SNAP." - zfs send -i $PREV_SNAP $LAST_SNAP | $BACKUP_SAVE_CMD + $PFZFS send -i $PREV_SNAP $LAST_SNAP | $BACKUP_SAVE_CMD check_failure $? "Error performing incremental backup of $dataset." ;; "full") print_note "Starting ZFS send of $LAST_SNAP." - zfs send $LAST_SNAP | $BACKUP_SAVE_CMD + $PFZFS send $LAST_SNAP | $BACKUP_SAVE_CMD check_failure $? "Error performing full backup of $dataset." ;; esac @@ -826,7 +836,7 @@ function auto_include { *false | false*) ;; *) - zfs set com.sun:auto-snapshot=true $pool + $PFZFS set com.sun:auto-snapshot=true $pool ;; esac fi diff --git a/src/postinstall b/src/postinstall index a59c173..a1a4d07 100755 --- a/src/postinstall +++ b/src/postinstall @@ -25,6 +25,58 @@ # Use is subject to license terms. # -# a postinstall script - it should import the manifests -# and enable the service -echo "Post install script doing nathing!" +# a postinstall script - adds zfssnap role. +# Return 0 if a user exists, 1 otherwise. +# + +# Check if the first argument is 0, settting our return +# variable to an error otherwise +# +function check_error { + RETURN_CODE=$1 + ERROR="$2" + if [ "$RETURN_CODE" -ne 0 ] ; then + echo "ERROR: $ERROR" + fi +} + +function user_exists { + typeset USER=$1 + if /usr/bin/grep ^$USER: $BASEDIR/etc/passwd > /dev/null ; then + return 0 + else + return 1 + fi +} + +function auth_exists { + typeset AUTH=$1 + if /usr/bin/grep ^$AUTH: $BASEDIR/etc/security/auth_attr > /dev/null ; then + return 0 + else + return 1 + fi +} + +# add our authorization +if ! auth_exists solaris.smf.manage.zfs-auto-snapshot; then + echo "solaris.smf.manage.zfs-auto-snapshot:::Manage the ZFS Automatic Snapshot Service::" \ + >> /etc/security/auth_attr +fi + +# add the zfssnap role - probably only works on a local system :-( +if ! user_exists zfssnap; then + /usr/sbin/roleadd -d /export/home/zfssnap -c "ZFS Automatic Snapshots role" \ + -P "ZFS File System Management" \ + -A solaris.smf.manage.zfs-auto-snapshot -m zfssnap + check_error $? "Unable to create zfssnap role!" + /usr/bin/passwd -r files -N zfssnap + check_error $? "Unable to make zfssnap a no-password account" + + # make sure their path has /usr/sbin in it + echo "PATH=/usr/sbin:\${PATH}" >> /export/home/zfssnap/.profile + echo "export PATH" >> /export/home/zfssnap/.profile +else + echo "zfssnap role already exists." +fi + diff --git a/src/r.manifest b/src/r.manifest new file mode 100755 index 0000000..489f786 --- /dev/null +++ b/src/r.manifest @@ -0,0 +1,83 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# r.manifest - smf(5) manifest remove class action script +# + +if [ "$PKG_INSTALL_ROOT" != "" -a "$PKG_INSTALL_ROOT" != "/" ]; then + # + # We can't safely disable the service in this case. + # + smf_alive=no +else + # + # We can verify if the service is disabled prior to + # removal. + # + if [ -r /etc/svc/volatile/repository_door ]; then + smf_alive=yes + fi +fi + +MFSTSCAN=/lib/svc/bin/mfstscan +SVCCFG=/usr/sbin/svccfg +SVCPROP=/usr/bin/svcprop + +while read mfst; do + if [ "$smf_alive" = "yes" ]; then + ENTITIES=`$SVCCFG inventory $mfst` + + for fmri in $ENTITIES; do + # + # Determine whether any of our instances are + # enabled. + # + en_p=`$SVCPROP -C -p general/enabled $fmri 2>/dev/null` + en_o=`$SVCPROP -C -p general_ovr/enabled $fmri 2>/dev/null` + + if [ "$en_p" = "true" -o "$en_o" = "true" ]; then + echo "$fmri remains enabled; aborting" + exit 1 + fi + + $SVCCFG delete $fmri + done + + # + # Delete the manifest hash value. + # + pg_name=`$MFSTSCAN -t $mfst` + if $SVCPROP -q -p $pg_name smf/manifest; then + $SVCCFG -s smf/manifest delpg $pg_name + fi + fi + + /usr/bin/rm $mfst +done + +exit 0 diff --git a/src/var/svc/manifest/system/filesystem/auto-snapshot-daily.xml b/src/var/svc/manifest/system/filesystem/auto-snapshot-daily.xml index 0c20d8e..81ed4dd 100644 --- a/src/var/svc/manifest/system/filesystem/auto-snapshot-daily.xml +++ b/src/var/svc/manifest/system/filesystem/auto-snapshot-daily.xml @@ -21,13 +21,21 @@ snapshots into the past. type='method' name='start' exec='/lib/svc/method/zfs-auto-snapshot start' - timeout_seconds='0' /> + timeout_seconds='0'> + + + + + timeout_seconds='0' > + + + + diff --git a/src/var/svc/manifest/system/filesystem/auto-snapshot-frequent.xml b/src/var/svc/manifest/system/filesystem/auto-snapshot-frequent.xml index 6701fd7..ee3179b 100644 --- a/src/var/svc/manifest/system/filesystem/auto-snapshot-frequent.xml +++ b/src/var/svc/manifest/system/filesystem/auto-snapshot-frequent.xml @@ -17,19 +17,27 @@ com.sun:auto-snapshot:frequent=true every + + + + + + + type='method' + name='stop' + exec='/lib/svc/method/zfs-auto-snapshot stop' + timeout_seconds='0' > + + + + - - - + diff --git a/src/var/svc/manifest/system/filesystem/auto-snapshot-hourly.xml b/src/var/svc/manifest/system/filesystem/auto-snapshot-hourly.xml index eec69bf..76f0e9f 100644 --- a/src/var/svc/manifest/system/filesystem/auto-snapshot-hourly.xml +++ b/src/var/svc/manifest/system/filesystem/auto-snapshot-hourly.xml @@ -18,16 +18,24 @@ and keeps 24 of these snapshots into the past. + type='method' + name='start' + exec='/lib/svc/method/zfs-auto-snapshot start' + timeout_seconds='0'> + + + + - + + + + + diff --git a/src/var/svc/manifest/system/filesystem/auto-snapshot-monthly.xml b/src/var/svc/manifest/system/filesystem/auto-snapshot-monthly.xml index d4a9178..1b7bcfe 100644 --- a/src/var/svc/manifest/system/filesystem/auto-snapshot-monthly.xml +++ b/src/var/svc/manifest/system/filesystem/auto-snapshot-monthly.xml @@ -18,16 +18,24 @@ and keeps 12 of these snapshots into the past. + type='method' + name='start' + exec='/lib/svc/method/zfs-auto-snapshot start' + timeout_seconds='0'> + + + + - + + + + + diff --git a/src/var/svc/manifest/system/filesystem/auto-snapshot-weekly.xml b/src/var/svc/manifest/system/filesystem/auto-snapshot-weekly.xml index fa41274..bea8d0e 100644 --- a/src/var/svc/manifest/system/filesystem/auto-snapshot-weekly.xml +++ b/src/var/svc/manifest/system/filesystem/auto-snapshot-weekly.xml @@ -18,16 +18,24 @@ and keeps 4 of these snapshots into the past. + type='method' + name='start' + exec='/lib/svc/method/zfs-auto-snapshot start' + timeout_seconds='0'> + + + + - + + + + + diff --git a/src/var/svc/manifest/system/filesystem/zfs-auto-snapshot.xml b/src/var/svc/manifest/system/filesystem/zfs-auto-snapshot.xml index a8a77cf..b7e1f71 100755 --- a/src/var/svc/manifest/system/filesystem/zfs-auto-snapshot.xml +++ b/src/var/svc/manifest/system/filesystem/zfs-auto-snapshot.xml @@ -56,6 +56,14 @@ + + + + + +