diff options
Diffstat (limited to 'tests/zfs-tests/tests/functional/history/history_common.kshlib')
-rw-r--r-- | tests/zfs-tests/tests/functional/history/history_common.kshlib | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/tests/zfs-tests/tests/functional/history/history_common.kshlib b/tests/zfs-tests/tests/functional/history/history_common.kshlib new file mode 100644 index 000000000000..e1f1d06d272c --- /dev/null +++ b/tests/zfs-tests/tests/functional/history/history_common.kshlib @@ -0,0 +1,416 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Copyright (c) 2013 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/history/history.cfg + +function run_and_verify +{ + typeset user pool + while getopts "p:u:" opt; do + case $opt in + p) + pool=$OPTARG + ;; + u) + user=$OPTARG + ;; + esac + done + shift $(($OPTIND - 1)) + + pool=${pool:-$TESTPOOL} + user=${user:-"root"} + fullcmd="$1" + flags="$2" + + if is_linux; then + histcmd=$($ECHO $fullcmd | $SED 's/^.*\/\(zpool .*\).*$/\1/') + histcmd=$($ECHO $histcmd | $SED 's/^.*\/\(zfs .*\).*$/\1/') + else + histcmd=$($ECHO $fullcmd | $SED 's/\/usr\/sbin\///g') + fi + + cmd=$($ECHO $histcmd | $AWK '{print $1}') + subcmd=$($ECHO $histcmd | $AWK '{print $2}') + + # If we aren't running zpool or zfs, something is wrong + [[ $cmd == "zpool" || $cmd == "zfs" ]] || \ + log_fail "run_and_verify called with \"$cmd ($fullcmd)\"" + + # If this is a 'zfs receive' truncate the stdin redirect + [[ $subcmd == "receive" || $subcmd == "recv" ]] && \ + histcmd=${histcmd%% <*} + + # Run the command as the specified user, and find the new history. + $ZPOOL history $flags $pool > $OLD_HISTORY 2>/dev/null + if [[ $user == "root" ]]; then + log_must eval "$fullcmd" + else + log_must $SU $user -c "eval $fullcmd" + fi + $ZPOOL history $flags $pool > $TMP_HISTORY 2>/dev/null + $DIFF $OLD_HISTORY $TMP_HISTORY | $GREP "^> " | $SED 's/^> //g' \ + > $NEW_HISTORY + + # Verify what's common to every case, regardless of zpool history flags. + $GREP "$histcmd" $NEW_HISTORY >/dev/null 2>&1 || \ + log_fail "Didn't find \"$histcmd\" in pool history" + + # If 'zpool history' was called without any flags, then we're done. + [[ -z $flags ]] && return + + # Verify the new history in cases that are more interesting because + # additional information is logged with -i or -l. + + [[ $flags =~ "i" ]] && log_must verify_$subcmd "$histcmd" "$subcmd" \ + "$flags" + [[ $flags =~ "l" ]] && log_must verify_long "$histcmd" "$user" "$flags" +} + +function verify_long +{ + typeset cmd=$1 + typeset user=$2 + typeset flags=$3 + + [[ $flags =~ "l" ]] || return 1 + + typeset uid=$($ID -u $user) + typeset hname=$($HOSTNAME) + if ! is_global_zone; then + hname=$hname:$($ZONENAME) + fi + + $GREP "$cmd \[user $uid ($user) on $hname\]" $NEW_HISTORY >/dev/null \ + 2>&1 + if [[ $? != 0 ]]; then + log_note "Couldn't find long information for \"$cmd\"" + return 1 + fi + + return 0 +} + +function verify_hold +{ + typeset cmd=$1 + typeset subcmd=$2 + typeset flags=$3 + + [[ $flags =~ "i" ]] || return 1 + + typeset tag=$($ECHO $cmd | $AWK '{print $4}') + typeset fullname=${cmd##* } + typeset dsname=${fullname%%@*} + typeset snapname=${fullname##*@} + + # This works whether or not the hold was recursive + for ds in $($ZFS list -r -Ho name -t snapshot $dsname | \ + $GREP "@$snapname"); do + $GREP "$subcmd $ds ([0-9]*) tag=$tag" $NEW_HISTORY \ + >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find hold on $ds with $tag" + return 1 + fi + done + + return 0 +} + +function verify_release +{ + # hold and release formats only differ by the subcommand name, so + # simply reuse the hold function. + verify_hold "$1" "release" "$3" +} + +function verify_rollback +{ + typeset cmd=$1 + typeset flags=$3 + + [[ $flags =~ "i" ]] || return 1 + + typeset fullname=${cmd##* } + typeset dsname=${fullname%%@*} + typeset parent_fs=${dsname##*/} + typeset rb_fs=${dsname}/%rollback + typeset snapname=${fullname##*@} + + $GREP "clone swap $rb_fs ([0-9]*) parent=$parent_fs" $NEW_HISTORY \ + >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find rollback clone swap in pool history" + return 1 + fi + + $GREP "destroy $rb_fs" $NEW_HISTORY >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find rollback destroy in pool history" + return 1 + fi + + return 0 +} + +function verify_inherit +{ + typeset cmd=$1 + typeset flags=$3 + + [[ $flags =~ "i" ]] || return 1 + + typeset dsname=${cmd##* } + typeset prop=${cmd% *} + prop=${prop##* } + + # This works whether or not the inherit was recursive + for ds in $($ZFS list -r -Ho name -t filesystem $dsname); do + $GREP "$subcmd $ds ([0-9]*) ${prop}=" $NEW_HISTORY >/dev/null \ + 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find inherit history for $ds" + return 1 + fi + done + + return 0 +} + +function verify_allow +{ + typeset cmd=$1 + typeset subcmd=$2 + typeset flags=$3 + + [[ $flags =~ "i" ]] || return 1 + [[ $subcmd == "allow" ]] && subcmd="update" + [[ $subcmd == "unallow" ]] && subcmd="remove" + typeset is_set lflag dflag dsname gname gid uname uid opt str code tmp + + # + # Here, we determine three things: + # - Whether we're operating on a set or an indivdual permission (which + # dictates the case of the first character in the code) + # - The name of the dataset we're operating on. + # - Whether the operation applies locally or to descendent datasets (or + # both) + # + $ECHO $cmd | $AWK '{i = NF - 1; print $i}' | $GREP '@' >/dev/null \ + 2>&1 && is_set=1 + dsname=${cmd##* } + [[ $cmd =~ "-l " ]] && lflag=1 + [[ $cmd =~ "-d " ]] && dflag=1 + if [[ -z $lflag && -z $dflag ]]; then + lflag=1 + dflag=1 + fi + + # + # For each of the five cases below, the operation is essentially the + # same. First, use the command passed in to determine what the code at + # the end of the pool history will be. The specifics of the code are + # described in a block comment at the top of dsl_deleg.c. Once that's + # been assembled, check for its presence in the history, and return + # success or failure accordingly. + # + if [[ $cmd =~ "-s " ]]; then + str="s-\$@" + [[ -n $is_set ]] && str="S-\$@" + tmp=${cmd#*@} + code="$str${tmp% *}" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + elif [[ $cmd =~ "-c " ]]; then + str="c-\$" + [[ -n $is_set ]] && str="C-\$" + tmp=${cmd#*-c} + code="$str${tmp% *}" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + elif [[ $cmd =~ "-u " ]]; then + str="u" + [[ -n $is_set ]] && str="U" + tmp=${cmd##*-u } + opt=$($ECHO $tmp | $AWK '{print $2}') + uid=$($ID -u ${tmp%% *}) + if [[ -n $lflag ]]; then + code="${str}l\$$uid $opt" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + fi + if [[ -n $dflag ]]; then + code="${str}d\$$uid $opt" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + fi + elif [[ $cmd =~ "-g " ]]; then + str="g" + [[ -n $is_set ]] && str="G" + tmp=${cmd##*-g } + opt=$($ECHO $tmp | $AWK '{print $2}') + gid=$($AWK -F: "/^${tmp%% *}:/ {print \$3}" /etc/group) + if [[ -n $lflag ]]; then + code="${str}l\$$gid $opt" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + fi + if [[ -n $dflag ]]; then + code="${str}d\$$gid $opt" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + fi + elif [[ $cmd =~ "-e " ]]; then + str="e" + [[ -n $is_set ]] && str="E" + opt=${cmd##*-e } + opt=${opt%% *} + if [[ -n $lflag ]]; then + code="${str}l\$ $opt" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + fi + if [[ -n $dflag ]]; then + code="${str}d\$ $opt" + $GREP "permission $subcmd $dsname ([0-9]*) $code" \ + $NEW_HISTORY >/dev/null 2>&1 + if [ $? != 0 ]]; then + log_note "Couldn't find $code in $NEW_HISTORY" + return 1 + fi + fi + else + log_note "Can't parse command \"$cmd\"" + return 1 + fi + + return 0 +} + +function verify_unallow +{ + # + # The unallow and allow history have the same format, except the former + # logs "permission removed" and the latter "permission updated" so + # simply reuse the allow function. + # + verify_allow "$1" "unallow" "$3" +} + +function verify_destroy +{ + typeset cmd=$1 + typeset flags=$3 + + # This function doesn't currently verifiy the zpool command. + [[ ${cmd%% *} == "zfs" ]] || return 1 + [[ $flags =~ "i" ]] || return 1 + + typeset dsname=${cmd##* } + [[ $dsname =~ "@" ]] && typeset is_snap=1 + + if [[ -n $is_snap ]]; then + $GREP "ioctl destroy_snaps" $NEW_HISTORY >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find ioctl while destroying $dsname" + return 1 + fi + fi + + # This should be present for datasets and snapshots alike + $GREP "destroy $dsname" $NEW_HISTORY >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find \"destroy\" for $dsname" + return 1 + fi + + return 0 +} + +function verify_snapshot +{ + typeset cmd=$1 + typeset flags=$3 + + [[ $flags =~ "i" ]] || return 1 + + typeset fullname=${cmd##* } + typeset dsname=${fullname%%@*} + typeset snapname=${fullname##*@} + + $GREP "\[txg:[0-9]*\] $subcmd $fullname ([0-9]*)" $NEW_HISTORY \ + >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find snapshot command for $fullname" + return 1 + fi + + # This works whether or not the snapshot was recursive + for ds in $($ZFS list -r -Ho name -t snapshot $dsname | \ + $GREP "@$snapname"); do + $GREP "^[ ]* $ds$" $NEW_HISTORY >/dev/null 2>&1 + if [[ $? != 0 ]]; then + log_note "Didn't find \"ioctl snapshot\" for $ds" + return 1 + fi + done + + return 0 +} |