mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 18:40:43 +03:00
Add zfs create dryrun
Adds the ability to sanity check zfs create arguments and to see the value of any additional properties that will local to the dataset. For example, automation that may need to adjust quota on a parent filesystem before creating a volume may call `zfs create -nP -V <size> <volume>` to obtain the value of refreservation. This adds the following options to zfs create: - -n dry-run (no-op) - -v verbose - -P parseable (implies verbose) Reviewed-by: Ryan Moeller <ryan@ixsystems.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Matt Ahrens <matt@delphix.com> Reviewed-by: Jerry Jelinek <jerry.jelinek@joyent.com> Signed-off-by: Mike Gerdts <mike.gerdts@joyent.com> Closes #8974
This commit is contained in:
committed by
Brian Behlendorf
parent
93e28d661e
commit
d45d7f08fa
@@ -143,7 +143,7 @@ tests = ['zfs_create_001_pos', 'zfs_create_002_pos', 'zfs_create_003_pos',
|
||||
'zfs_create_007_pos', 'zfs_create_008_neg', 'zfs_create_009_neg',
|
||||
'zfs_create_010_neg', 'zfs_create_011_pos', 'zfs_create_012_pos',
|
||||
'zfs_create_013_pos', 'zfs_create_014_pos', 'zfs_create_encrypted',
|
||||
'zfs_create_crypt_combos']
|
||||
'zfs_create_crypt_combos', 'zfs_create_dryrun', 'zfs_create_verbose']
|
||||
tags = ['functional', 'cli_root', 'zfs_create']
|
||||
|
||||
[tests/functional/cli_root/zfs_destroy]
|
||||
|
||||
@@ -17,7 +17,9 @@ dist_pkgdata_SCRIPTS = \
|
||||
zfs_create_013_pos.ksh \
|
||||
zfs_create_014_pos.ksh \
|
||||
zfs_create_encrypted.ksh \
|
||||
zfs_create_crypt_combos.ksh
|
||||
zfs_create_crypt_combos.ksh \
|
||||
zfs_create_dryrun.ksh \
|
||||
zfs_create_verbose.ksh
|
||||
|
||||
dist_pkgdata_DATA = \
|
||||
properties.kshlib \
|
||||
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
#!/bin/ksh -p
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2019 Joyent, Inc.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# zfs create -n should perform basic sanity checking but should never create a
|
||||
# dataset. If -v and/or -P are used, it should verbose about what would be
|
||||
# created if sanity checks pass.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Attempt to create a file system and a volume using various combinations of
|
||||
# -n with -v and -P.
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
#
|
||||
# Verifies that valid commands with -n and without -[vP]:
|
||||
# - succeed
|
||||
# - do not create a dataset
|
||||
# - do not generate output
|
||||
#
|
||||
function dry_create_no_output
|
||||
{
|
||||
typeset -a cmd=(zfs create -n "$@")
|
||||
|
||||
log_note "$0: ${cmd[@]}"
|
||||
log_must "${cmd[@]}"
|
||||
datasetexists "$TESTPOOL/$TESTFS1" &&
|
||||
log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
|
||||
typeset out=$("${cmd[@]}" 2>&1)
|
||||
[[ -z "$out" ]] ||
|
||||
log_fail "unexpected output '$out' from '${cmd[@]}'"
|
||||
}
|
||||
|
||||
#
|
||||
# Verifies that commands with invalid properties or invalid property values
|
||||
# - fail
|
||||
# - do not create a dataset
|
||||
# - generate a message on stderr
|
||||
#
|
||||
function dry_create_error
|
||||
{
|
||||
typeset -a cmd=(zfs create -n "$@")
|
||||
|
||||
log_note "$0: ${cmd[@]}"
|
||||
log_mustnot "${cmd[@]}"
|
||||
datasetexists "$TESTPOOL/$TESTFS1" &&
|
||||
log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
|
||||
typeset out=$("${cmd[@]}" 2>&1 >/dev/null)
|
||||
[[ -z "$out" ]] &&
|
||||
log_fail "expected an error message but got none from '${cmd[@]}'"
|
||||
}
|
||||
|
||||
#
|
||||
# Verifies that dry-run commands with parseable output
|
||||
# - succeed
|
||||
# - do not create datasets
|
||||
# - generate parseable output on stdout
|
||||
# - output matches expectations
|
||||
#
|
||||
function dry_create_parseable
|
||||
{
|
||||
typeset -n exp=$1
|
||||
shift
|
||||
typeset -a cmd=(zfs create -Pn "$@")
|
||||
typeset ds=${cmd[${#cmd[@]} - 1]}
|
||||
typeset out
|
||||
typeset -a toks
|
||||
typeset -a props
|
||||
typeset found_create=false
|
||||
|
||||
log_note "$0: ${cmd[@]}"
|
||||
out=$("${cmd[@]}")
|
||||
(( $? == 0 )) ||
|
||||
log_fail "unexpected failure getting stdout from '${cmd[@]}'"
|
||||
datasetexists "$TESTPOOL/$TESTFS1" &&
|
||||
log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
|
||||
echo "$out" | while IFS=$'\t' read -A toks; do
|
||||
log_note "verifying ${toks[@]}"
|
||||
case ${toks[0]} in
|
||||
create)
|
||||
log_must test "${#toks[@]}" -eq 2
|
||||
log_must test "${toks[1]}" == "$ds"
|
||||
found_create="yes, I found create"
|
||||
;;
|
||||
property)
|
||||
log_must test "${#toks[@]}" -eq 3
|
||||
typeset prop=${toks[1]}
|
||||
typeset val=${toks[2]}
|
||||
if [[ -z "${exp[$prop]}" ]]; then
|
||||
log_fail "unexpectedly got property '$prop'"
|
||||
fi
|
||||
# We may not know the exact value a property will take
|
||||
# on. This is the case for at least refreservation.
|
||||
if [[ ${exp[$prop]} != "*" ]]; then
|
||||
log_must test "${exp[$prop]}" == "$val"
|
||||
fi
|
||||
unset exp[$prop]
|
||||
;;
|
||||
*)
|
||||
log_fail "Unexpected line ${toks[@]}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_must test "$found_create" == "yes, I found create"
|
||||
log_must test "extra props: ${!exp[@]}" == "extra props: "
|
||||
}
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if datasetexists "$TESTPOOL/$TESTFS1"; then
|
||||
log_must zfs destroy -r "$TESTPOOL/$TESTFS1"
|
||||
fi
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
log_assert "zfs create -n creates nothing but can describe what would be" \
|
||||
"created"
|
||||
|
||||
# Typical creations should succeed
|
||||
dry_create_no_output "$TESTPOOL/$TESTFS1"
|
||||
dry_create_no_output -V 10m "$TESTPOOL/$TESTFS1"
|
||||
# It shouldn't do a space check right now
|
||||
dry_create_no_output -V 100t "$TESTPOOL/$TESTFS1"
|
||||
# It shouldn't create parent datasets either
|
||||
dry_create_no_output -p "$TESTPOOL/$TESTFS1/$TESTFS2"
|
||||
dry_create_no_output -pV 10m "$TESTPOOL/$TESTFS1/$TESTFS2"
|
||||
|
||||
# Various invalid properties should be recognized and result in an error
|
||||
dry_create_error -o nosuchprop=42 "$TESTPOOL/$TESTFS1"
|
||||
dry_create_error -b 1234 -V 10m "$TESTPOOL/$TESTFS1"
|
||||
|
||||
# Parseable output should be parseable.
|
||||
typeset -A expect
|
||||
expect=([compression]=on)
|
||||
dry_create_parseable expect -o compression=on "$TESTPOOL/$TESTFS1"
|
||||
|
||||
# Sparse volumes should not get a gratuitous refreservation
|
||||
expect=([volblocksize]=4096 [volsize]=$((1024 * 1024 * 10)))
|
||||
dry_create_parseable expect -b 4k -V 10m -s "$TESTPOOL/$TESTFS1"
|
||||
|
||||
# Non-sparse volumes should have refreservation
|
||||
expect=(
|
||||
[volblocksize]=4096
|
||||
[volsize]=$((1024 * 1024 * 10))
|
||||
[refreservation]="*"
|
||||
)
|
||||
dry_create_parseable expect -b 4k -V 10m "$TESTPOOL/$TESTFS1"
|
||||
|
||||
log_pass "zfs create -n creates nothing but can describe what would be" \
|
||||
"created"
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
#!/bin/ksh -p
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2019 Joyent, Inc.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
|
||||
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# zfs create -P without -n should be verbose about dataset creation.
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Attempt to create a file system and a volume using various properties
|
||||
# and -P
|
||||
# 2. Exercise the combination of -p and -P.
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
#
|
||||
# Verifies that non dry-run commands with parseable output
|
||||
# - succeed
|
||||
# - create datasets
|
||||
# - generate parseable output on stdout
|
||||
# - output matches expectations
|
||||
#
|
||||
function dry_create_parseable
|
||||
{
|
||||
typeset -n exp=$1
|
||||
shift
|
||||
typeset -a cmd=(zfs create -P "$@")
|
||||
typeset ds=${cmd[${#cmd[@]} - 1]}
|
||||
typeset out
|
||||
typeset -a toks
|
||||
typeset -a props
|
||||
typeset found_create=false
|
||||
typeset create_ancestors=
|
||||
typeset opt
|
||||
|
||||
# Parse the arguments to see if -p was used.
|
||||
while getopts :PV:b:ospv opt; do
|
||||
case $opt in
|
||||
p) create_ancestors=needed ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_note "$0: ${cmd[@]}"
|
||||
out=$("${cmd[@]}")
|
||||
(( $? == 0 )) ||
|
||||
log_fail "unexpected failure getting stdout from '${cmd[@]}'"
|
||||
datasetexists "$TESTPOOL/$TESTFS1" ||
|
||||
log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
|
||||
echo "$out" | while IFS=$'\t' read -A toks; do
|
||||
log_note "verifying ${toks[@]}"
|
||||
case ${toks[0]} in
|
||||
create_ancestors)
|
||||
case "$create_ancestors" in
|
||||
needed)
|
||||
log_must test "${toks[1]}" == "$ds"
|
||||
create_ancestors="found ${toks[1]}"
|
||||
;;
|
||||
found*)
|
||||
log_fail "multiple ancestor creation" \
|
||||
"$create_ancestors and ${toks[1]}"
|
||||
;;
|
||||
"")
|
||||
log_fail "unexpected create_ancestors"
|
||||
;;
|
||||
*)
|
||||
log_fail "impossible error: fix the test"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
create)
|
||||
log_must test "${#toks[@]}" -eq 2
|
||||
log_must test "${toks[1]}" == "$ds"
|
||||
found_create="yes, I found create"
|
||||
;;
|
||||
property)
|
||||
log_must test "${#toks[@]}" -eq 3
|
||||
typeset prop=${toks[1]}
|
||||
typeset val=${toks[2]}
|
||||
if [[ -z "${exp[$prop]}" ]]; then
|
||||
log_fail "unexpectedly got property '$prop'"
|
||||
fi
|
||||
# We may not know the exact value a property will take
|
||||
# on. This is the case for at least refreservation.
|
||||
if [[ ${exp[$prop]} != "*" ]]; then
|
||||
log_must test "${exp[$prop]}" == "$val"
|
||||
fi
|
||||
unset exp[$prop]
|
||||
;;
|
||||
*)
|
||||
log_fail "Unexpected line ${toks[@]}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_must test "$found_create" == "yes, I found create"
|
||||
log_must test "extra props: ${!exp[@]}" == "extra props: "
|
||||
|
||||
case "$create_ancestors" in
|
||||
"")
|
||||
log_must_busy zfs destroy "$ds"
|
||||
;;
|
||||
"found $ds")
|
||||
log_must_busy zfs destroy -r "$(echo "$ds" | cut -d/ -f1-2)"
|
||||
;;
|
||||
needed)
|
||||
log_fail "Expected but did not find create_ancestors"
|
||||
;;
|
||||
*)
|
||||
log_fail "Unexpected value for create_ancestors:" \
|
||||
"$create_ancestors"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if datasetexists "$TESTPOOL/$TESTFS1"; then
|
||||
log_must_busy zfs destroy -r "$TESTPOOL/$TESTFS1"
|
||||
fi
|
||||
}
|
||||
log_onexit cleanup
|
||||
|
||||
log_assert "zfs create -v creates datasets verbosely"
|
||||
|
||||
# Parseable output should be parseable.
|
||||
typeset -A expect
|
||||
expect=([compression]=on)
|
||||
dry_create_parseable expect -o compression=on "$TESTPOOL/$TESTFS1"
|
||||
|
||||
# Ancestor creation with -p should emit relevant line
|
||||
expect=([compression]=on)
|
||||
dry_create_parseable expect -p -o compression=on "$TESTPOOL/$TESTFS1"
|
||||
expect=([compression]=on)
|
||||
dry_create_parseable expect -p -o compression=on "$TESTPOOL/$TESTFS1/$TESTVOL"
|
||||
|
||||
# Sparse volumes should not get a gratuitous refreservation
|
||||
expect=([volblocksize]=4096 [volsize]=$((1024 * 1024 * 10)))
|
||||
dry_create_parseable expect -b 4k -V 10m -s "$TESTPOOL/$TESTFS1"
|
||||
|
||||
# Non-sparse volumes should have refreservation
|
||||
expect=(
|
||||
[volblocksize]=4096
|
||||
[volsize]=$((1024 * 1024 * 10))
|
||||
[refreservation]="*"
|
||||
)
|
||||
dry_create_parseable expect -b 4k -V 10m "$TESTPOOL/$TESTFS1"
|
||||
|
||||
log_pass "zfs create -v creates datasets verbosely"
|
||||
Reference in New Issue
Block a user