1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy of the CDDL is also available via the Internet at
12# http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
19#
20
21. $STF_SUITE/include/libtest.shlib
22. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
23
24#
25# DESCRIPTION:
26# Verify ZFS property override (-o) and exclude (-x) options work when
27# receiving a send stream
28#
29# STRATEGY:
30# 1. Create a filesystem with children.
31# 2. Snapshot the filesystems.
32# 3. Create various send streams (full, incremental, replication) and verify
33#    we can both override and exclude native and user properties.
34#
35
36verify_runnable "both"
37
38function cleanup
39{
40	log_must rm -f $streamfile_full
41	log_must rm -f $streamfile_incr
42	log_must rm -f $streamfile_repl
43	log_must rm -f $streamfile_trun
44	destroy_dataset "$orig" "-rf"
45	destroy_dataset "$dest" "-rf"
46}
47
48log_assert "ZFS receive property override and exclude options work as expected."
49log_onexit cleanup
50
51orig=$TESTPOOL/$TESTFS1
52origsub=$orig/sub
53dest=$TESTPOOL/$TESTFS2
54destsub=$dest/sub
55typeset userprop=$(valid_user_property 8)
56typeset userval=$(user_property_value 8)
57typeset streamfile_full=$TESTDIR/streamfile_full.$$
58typeset streamfile_incr=$TESTDIR/streamfile_incr.$$
59typeset streamfile_repl=$TESTDIR/streamfile_repl.$$
60typeset streamfile_trun=$TESTDIR/streamfile_trun.$$
61
62#
63# 3.1 Verify we can't specify the same property in multiple -o or -x options
64#     or an invalid value was specified.
65#
66# Create a full send stream
67log_must zfs create $orig
68log_must zfs snapshot $orig@snap1
69log_must eval "zfs send $orig@snap1 > $streamfile_full"
70# Verify we reject invalid options
71log_mustnot eval "zfs recv $dest -o atime < $streamfile_full"
72log_mustnot eval "zfs recv $dest -x atime=off < $streamfile_full"
73log_mustnot eval "zfs recv $dest -o atime=off -x atime < $streamfile_full"
74log_mustnot eval "zfs recv $dest -o atime=off -o atime=on < $streamfile_full"
75log_mustnot eval "zfs recv $dest -x atime -x atime < $streamfile_full"
76log_mustnot eval "zfs recv $dest -o version=1 < $streamfile_full"
77log_mustnot eval "zfs recv $dest -x version < $streamfile_full"
78log_mustnot eval "zfs recv $dest -x normalization < $streamfile_full"
79# Verify we also reject invalid ZVOL options
80log_must zfs create -V 32K -s $orig/zvol
81log_must eval "zfs send $orig@snap1 > $streamfile_full"
82log_mustnot eval "zfs recv $dest -x volsize < $streamfile_full"
83log_mustnot eval "zfs recv $dest -o volsize=32K < $streamfile_full"
84# Cleanup
85block_device_wait
86log_must_busy zfs destroy -r -f $orig
87
88#
89# 3.2 Verify -o property=value works on streams without properties.
90#
91# Create a full send stream
92log_must zfs create $orig
93log_must zfs snapshot $orig@snap1
94log_must eval "zfs send $orig@snap1 > $streamfile_full"
95# Receive the full stream, override some properties
96log_must eval "zfs recv -o compression=on -o '$userprop:dest'='$userval' "\
97	"$dest < $streamfile_full"
98log_must eval "check_prop_source $dest compression on local"
99log_must eval "check_prop_source $dest '$userprop:dest' '$userval' local"
100# Cleanup
101log_must zfs destroy -r -f $orig
102log_must zfs destroy -r -f $dest
103
104#
105# 3.3 Verify -o property=value and -x work on both native and user properties
106#     for an incremental replication send stream.
107#
108# Create a dataset tree and receive it
109log_must zfs create $orig
110log_must zfs create $origsub
111log_must zfs snapshot -r $orig@snap1
112log_must eval "zfs send -R $orig@snap1 > $streamfile_repl"
113log_must eval "zfs recv $dest < $streamfile_repl"
114# Fill the datasets with properties and create an incremental replication stream
115log_must zfs snapshot -r $orig@snap2
116log_must zfs snapshot -r $orig@snap3
117log_must eval "zfs set copies=2 $orig"
118log_must eval "zfs set '$userprop:orig'='$userval' $orig"
119log_must eval "zfs set '$userprop:orig'='$userval' $origsub"
120log_must eval "zfs set '$userprop:snap'='$userval' $orig@snap1"
121log_must eval "zfs set '$userprop:snap'='$userval' $origsub@snap3"
122log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr"
123# Sets various combination of override and exclude options
124log_must eval "zfs recv -F -o atime=off -o '$userprop:dest2'='$userval' "\
125	"-o quota=123456789 -o checksum=sha512 -x compression "\
126        "-x '$userprop:orig' -x '$userprop:snap3' $dest < $streamfile_incr"
127# Verify we can correctly override and exclude properties
128log_must eval "check_prop_source $dest copies 2 received"
129log_must eval "check_prop_source $dest atime off local"
130log_must eval "check_prop_source $dest '$userprop:dest2' '$userval' local"
131log_must eval "check_prop_source $dest quota 123456789 local"
132log_must eval "check_prop_source $dest checksum sha512 local"
133log_must eval "check_prop_inherit $destsub copies $dest"
134log_must eval "check_prop_inherit $destsub atime $dest"
135log_must eval "check_prop_inherit $destsub checksum $dest"
136log_must eval "check_prop_inherit $destsub '$userprop:dest2' $dest"
137log_must eval "check_prop_source $destsub quota 0 default"
138log_must eval "check_prop_source $destsub compression on default"
139log_must eval "check_prop_missing $dest '$userprop:orig'"
140log_must eval "check_prop_missing $destsub '$userprop:orig'"
141log_must eval "check_prop_source " \
142	"$dest@snap1 '$userprop:snap' '$userval' received"
143log_must eval "check_prop_source " \
144	"$destsub@snap3 '$userprop:snap' '$userval' received"
145log_must eval "check_prop_missing $dest@snap3 '$userprop:snap3'"
146log_must eval "check_prop_missing $destsub@snap3 '$userprop:snap3'"
147# Cleanup
148log_must zfs destroy -r -f $orig
149log_must zfs destroy -r -f $dest
150
151#
152# 3.4 Verify '-x property' does not remove existing local properties and a
153#     modified sent property is received and updated to the new value but can
154#     still be excluded.
155#
156# Create a dataset tree
157log_must zfs create $orig
158log_must zfs create $origsub
159log_must zfs snapshot -r $orig@snap1
160log_must eval "zfs set copies=2 $orig"
161log_must eval "zfs set '$userprop:orig'='oldval' $orig"
162log_must eval "zfs set '$userprop:orig'='oldsubval' $origsub"
163log_must eval "zfs send -R $orig@snap1 > $streamfile_repl"
164log_must eval "zfs receive $dest < $streamfile_repl"
165log_must eval "check_prop_source $dest copies 2 received"
166log_must eval "check_prop_inherit $destsub copies $dest"
167log_must eval "check_prop_source $dest '$userprop:orig' 'oldval' received"
168log_must eval "check_prop_source $destsub '$userprop:orig' 'oldsubval' received"
169# Set new custom properties on both source and destination
170log_must eval "zfs set copies=3 $orig"
171log_must eval "zfs set '$userprop:orig'='newval' $orig"
172log_must eval "zfs set '$userprop:orig'='newsubval' $origsub"
173log_must eval "zfs set compression=gzip $dest"
174log_must eval "zfs set '$userprop:dest'='localval' $dest"
175# Receive the new stream, verify we preserve locally set properties
176log_must zfs snapshot -r $orig@snap2
177log_must zfs snapshot -r $orig@snap3
178log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr"
179log_must eval "zfs recv -F -x copies -x compression -x '$userprop:orig' " \
180	"-x '$userprop:dest' $dest < $streamfile_incr"
181log_must eval "check_prop_source $dest '$userprop:dest' 'localval' local"
182log_must eval "check_prop_received $dest '$userprop:orig' 'newval'"
183log_must eval "check_prop_received $destsub '$userprop:orig' 'newsubval'"
184log_must eval "check_prop_missing $dest '$userprop:orig'"
185log_must eval "check_prop_missing $destsub '$userprop:orig'"
186log_must eval "check_prop_source $dest copies 1 default"
187log_must eval "check_prop_received $dest copies 3"
188log_must eval "check_prop_source $destsub copies 1 default"
189log_must eval "check_prop_received $destsub copies '-'"
190log_must eval "check_prop_source $dest compression gzip local"
191log_must eval "check_prop_inherit $destsub compression $dest"
192# Cleanup
193log_must zfs destroy -r -f $orig
194log_must zfs destroy -r -f $dest
195
196#
197# 3.5 Verify we can exclude non-inheritable properties from a send stream
198#
199# Create a dataset tree and replication stream
200log_must zfs create $orig
201log_must zfs create $origsub
202log_must zfs snapshot -r $orig@snap1
203log_must eval "zfs set quota=123456789 $orig"
204log_must eval "zfs send -R $orig@snap1 > $streamfile_repl"
205# Receive the stream excluding non-inheritable properties
206log_must eval "zfs recv -F -x quota $dest < $streamfile_repl"
207log_must eval "check_prop_source $dest quota 0 default"
208log_must eval "check_prop_source $destsub quota 0 default"
209# Set some non-inheritable properties on the destination, verify we keep them
210log_must eval "zfs set quota=123456789 $dest"
211log_must eval "zfs set canmount=off $destsub"
212log_must zfs snapshot -r $orig@snap2
213log_must zfs snapshot -r $orig@snap3
214log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr"
215log_must eval "zfs recv -F -x quota -x canmount $dest < $streamfile_incr"
216log_must eval "check_prop_source $dest quota 123456789 local"
217log_must eval "check_prop_source $destsub quota 0 default"
218log_must eval "check_prop_source $destsub canmount off local"
219# Cleanup
220log_must zfs destroy -r -f $orig
221log_must zfs destroy -r -f $dest
222
223#
224# 3.6 Verify we correctly restore existing properties on a failed receive
225#
226# Receive a "clean" dataset tree
227log_must zfs create $orig
228log_must zfs create $origsub
229log_must zfs snapshot -r $orig@snap1
230log_must eval "zfs send -R $orig@snap1 > $streamfile_repl"
231log_must eval "zfs receive $dest < $streamfile_repl"
232# Set custom properties on the destination
233log_must eval "zfs set atime=off $dest"
234log_must eval "zfs set quota=123456789 $dest"
235log_must eval "zfs set '$userprop:orig'='$userval' $dest"
236log_must eval "zfs set '$userprop:origsub'='$userval' $destsub"
237# Create a truncated incremental replication stream
238mntpnt=$(get_prop mountpoint $orig)
239log_must eval "dd if=/dev/urandom of=$mntpnt/file bs=1024k count=10"
240log_must zfs snapshot -r $orig@snap2
241log_must zfs snapshot -r $orig@snap3
242log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr"
243log_must eval "dd if=$streamfile_incr of=$streamfile_trun bs=1024k count=9"
244# Receive the truncated stream, verify original properties are kept
245log_mustnot eval "zfs recv -F -o copies=3 -o quota=987654321 "\
246	"-o '$userprop:new'='badval' $dest < $streamfile_trun"
247log_must eval "check_prop_source $dest copies 1 default"
248log_must eval "check_prop_source $destsub copies 1 default"
249log_must eval "check_prop_source $dest atime off local"
250log_must eval "check_prop_inherit $destsub atime $dest"
251log_must eval "check_prop_source $dest quota 123456789 local"
252log_must eval "check_prop_source $destsub quota 0 default"
253log_must eval "check_prop_source $dest '$userprop:orig' '$userval' local"
254log_must eval "check_prop_inherit $destsub '$userprop:orig' $dest"
255log_must eval "check_prop_source $destsub '$userprop:origsub' '$userval' local"
256log_must eval "check_prop_missing $dest '$userprop:new'"
257# Cleanup
258log_must zfs destroy -r -f $orig
259log_must zfs destroy -r -f $dest
260
261#
262# 3.7 Verify we can receive a send stream excluding but not overriding
263#     properties invalid for the dataset type, in which case only the
264#     appropriate properties are set on the destination.
265log_must zfs create -V 128K -s $orig
266log_must zfs snapshot $orig@snap1
267log_must eval "zfs send $orig@snap1 > $streamfile_full"
268log_mustnot eval "zfs receive -o atime=off $dest < $streamfile_full"
269log_mustnot eval "zfs receive -o atime=off -x canmount $dest < $streamfile_full"
270log_must eval "zfs receive -x atime -x canmount $dest < $streamfile_full"
271log_must eval "check_prop_source $dest type volume -"
272log_must eval "check_prop_source $dest atime - -"
273log_must eval "check_prop_source $dest canmount - -"
274log_must_busy zfs destroy -r -f $orig
275log_must_busy zfs destroy -r -f $dest
276# Recursive sends also accept (and ignore) such overrides
277log_must zfs create $orig
278log_must zfs create -V 128K -s $origsub
279log_must zfs snapshot -r $orig@snap1
280log_must eval "zfs send -R $orig@snap1 > $streamfile_repl"
281log_must eval "zfs receive -o atime=off $dest < $streamfile_repl"
282log_must eval "check_prop_source $dest type filesystem -"
283log_must eval "check_prop_source $dest atime off local"
284log_must eval "check_prop_source $destsub type volume -"
285log_must eval "check_prop_source $destsub atime - -"
286# Cleanup
287block_device_wait
288log_must_busy zfs destroy -r -f $orig
289log_must_busy zfs destroy -r -f $dest
290
291#
292# 3.8 Verify 'zfs recv -x|-o' works correctly when used in conjunction with -d
293#     and -e options.
294#
295log_must zfs create -p $orig/1/2/3/4
296log_must eval "zfs set copies=2 $orig"
297log_must eval "zfs set atime=on $orig"
298log_must eval "zfs set '$userprop:orig'='oldval' $orig"
299log_must zfs snapshot -r $orig@snap1
300log_must eval "zfs send -R $orig/1/2@snap1 > $streamfile_repl"
301# Verify 'zfs recv -e'
302log_must zfs create $dest
303log_must eval "zfs receive -e -o copies=3 -x atime "\
304	"-o '$userprop:orig'='newval' $dest < $streamfile_repl"
305log_must datasetexists $dest/2/3/4
306log_must eval "check_prop_source $dest/2 copies 3 local"
307log_must eval "check_prop_inherit $dest/2/3/4 copies $dest/2"
308log_must eval "check_prop_source $dest/2/3/4 atime on default"
309log_must eval "check_prop_source $dest/2 '$userprop:orig' 'newval' local"
310log_must eval "check_prop_inherit $dest/2/3/4 '$userprop:orig' $dest/2"
311log_must zfs destroy -r -f $dest
312# Verify 'zfs recv -d'
313log_must zfs create $dest
314typeset fs="$(echo $orig | awk -F'/' '{print $NF}')"
315log_must eval "zfs receive -d -o copies=3 -x atime "\
316	"-o '$userprop:orig'='newval' $dest < $streamfile_repl"
317log_must datasetexists $dest/$fs/1/2/3/4
318log_must eval "check_prop_source $dest/$fs/1/2 copies 3 local"
319log_must eval "check_prop_inherit $dest/$fs/1/2/3/4 copies $dest/$fs/1/2"
320log_must eval "check_prop_source $dest/$fs/1/2/3/4 atime on default"
321log_must eval "check_prop_source $dest/$fs/1/2 '$userprop:orig' 'newval' local"
322log_must eval "check_prop_inherit $dest/$fs/1/2/3/4 '$userprop:orig' $dest/$fs/1/2"
323# We don't need to cleanup here
324
325log_pass "ZFS receive property override and exclude options passed."
326