]>
Commit | Line | Data |
---|---|---|
cae5b340 AX |
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 | ||
36 | verify_runnable "both" | |
37 | ||
38 | function 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 | log_must zfs destroy -r -f $orig | |
45 | log_must zfs destroy -r -f $dest | |
46 | } | |
47 | ||
48 | # | |
49 | # Verify property $2 is set from source $4 on dataset $1 and has value $3. | |
50 | # | |
51 | # $1 checked dataset | |
52 | # $2 user property | |
53 | # $3 property value | |
54 | # $4 source | |
55 | # | |
56 | function check_prop_source | |
57 | { | |
58 | typeset dataset="$1" | |
59 | typeset prop="$2" | |
60 | typeset value="$3" | |
61 | typeset source="$4" | |
62 | typeset chk_value=$(get_prop "$prop" "$dataset") | |
63 | typeset chk_source=$(get_source "$prop" "$dataset") | |
64 | ||
65 | if [[ "$chk_value" != "$value" || "$chk_source" != "$4" ]] | |
66 | then | |
67 | return 1 | |
68 | else | |
69 | return 0 | |
70 | fi | |
71 | } | |
72 | ||
73 | # | |
74 | # Verify target dataset $1 inherit property $2 from dataset $3. | |
75 | # | |
76 | # $1 checked dataset | |
77 | # $2 property | |
78 | # $3 inherited dataset | |
79 | # | |
80 | function check_prop_inherit | |
81 | { | |
82 | typeset checked_dtst="$1" | |
83 | typeset prop="$2" | |
84 | typeset inherited_dtst="$3" | |
85 | typeset inherited_value=$(get_prop "$prop" "$inherited_dtst") | |
86 | typeset value=$(get_prop "$prop" "$checked_dtst") | |
87 | typeset source=$(get_source "$prop" "$checked_dtst") | |
88 | ||
89 | if [[ "$value" != "$inherited_value" || \ | |
90 | "$source" != "inherited from $inherited_dtst" ]] | |
91 | then | |
92 | return 1 | |
93 | else | |
94 | return 0 | |
95 | fi | |
96 | } | |
97 | ||
98 | # | |
99 | # Verify property $2 received value on dataset $1 has value $3 | |
100 | # | |
101 | # $1 checked dataset | |
102 | # $2 property name | |
103 | # $3 checked value | |
104 | # | |
105 | function check_prop_received | |
106 | { | |
107 | typeset dataset="$1" | |
108 | typeset prop="$2" | |
109 | typeset value="$3" | |
110 | ||
111 | received=$(zfs get -H -o received "$prop" "$dataset") | |
112 | if (($? != 0)); then | |
113 | log_fail "Unable to get $prop received value for dataset " \ | |
114 | "$dataset" | |
115 | fi | |
116 | if [[ "$received" == "$value" ]] | |
117 | then | |
118 | return 0 | |
119 | else | |
120 | return 1 | |
121 | fi | |
122 | } | |
123 | ||
124 | # | |
125 | # Verify user property $2 is not set on dataset $1 | |
126 | # | |
127 | # $1 checked dataset | |
128 | # $2 property name | |
129 | # | |
130 | function check_prop_missing | |
131 | { | |
132 | typeset dataset="$1" | |
133 | typeset prop="$2" | |
134 | ||
135 | value=$(zfs get -H -o value "$prop" "$dataset") | |
136 | if (($? != 0)); then | |
137 | log_fail "Unable to get $prop value for dataset $dataset" | |
138 | fi | |
139 | if [[ "-" == "$value" ]] | |
140 | then | |
141 | return 0 | |
142 | else | |
143 | return 1 | |
144 | fi | |
145 | } | |
146 | ||
147 | log_assert "ZFS receive property override and exclude options work as expected." | |
148 | log_onexit cleanup | |
149 | ||
150 | orig=$TESTPOOL/$TESTFS1 | |
151 | origsub=$orig/sub | |
152 | dest=$TESTPOOL/$TESTFS2 | |
153 | destsub=$dest/sub | |
154 | typeset userprop=$(valid_user_property 8) | |
155 | typeset userval=$(user_property_value 8) | |
156 | typeset streamfile_full=$TESTDIR/streamfile_full.$$ | |
157 | typeset streamfile_incr=$TESTDIR/streamfile_incr.$$ | |
158 | typeset streamfile_repl=$TESTDIR/streamfile_repl.$$ | |
159 | typeset streamfile_trun=$TESTDIR/streamfile_trun.$$ | |
160 | ||
161 | # | |
162 | # 3.1 Verify we can't specify the same property in multiple -o or -x options | |
163 | # or an invalid value was specified. | |
164 | # | |
165 | # Create a full send stream | |
166 | log_must zfs create $orig | |
167 | log_must zfs snapshot $orig@snap1 | |
168 | log_must eval "zfs send $orig@snap1 > $streamfile_full" | |
169 | # Verify we reject invalid options | |
170 | log_mustnot eval "zfs recv $dest -o atime < $streamfile_full" | |
171 | log_mustnot eval "zfs recv $dest -x atime=off < $streamfile_full" | |
172 | log_mustnot eval "zfs recv $dest -o atime=off -x atime < $streamfile_full" | |
173 | log_mustnot eval "zfs recv $dest -o atime=off -o atime=on < $streamfile_full" | |
174 | log_mustnot eval "zfs recv $dest -x atime -x atime < $streamfile_full" | |
175 | log_mustnot eval "zfs recv $dest -o version=1 < $streamfile_full" | |
176 | log_mustnot eval "zfs recv $dest -x version < $streamfile_full" | |
177 | log_mustnot eval "zfs recv $dest -x normalization < $streamfile_full" | |
178 | # Verify we also reject invalid ZVOL options | |
179 | log_must zfs create -V 32K -s $orig/zvol | |
180 | log_must eval "zfs send $orig@snap1 > $streamfile_full" | |
181 | log_mustnot eval "zfs recv $dest -x volsize < $streamfile_full" | |
182 | log_mustnot eval "zfs recv $dest -o volsize=32K < $streamfile_full" | |
183 | # Cleanup | |
184 | block_device_wait | |
185 | log_must_busy zfs destroy -r -f $orig | |
186 | ||
187 | # | |
188 | # 3.2 Verify -o property=value works on streams without properties. | |
189 | # | |
190 | # Create a full send stream | |
191 | log_must zfs create $orig | |
192 | log_must zfs snapshot $orig@snap1 | |
193 | log_must eval "zfs send $orig@snap1 > $streamfile_full" | |
194 | # Receive the full stream, override some properties | |
195 | log_must eval "zfs recv -o compression=on -o '$userprop:dest'='$userval' "\ | |
196 | "$dest < $streamfile_full" | |
197 | log_must eval "check_prop_source $dest compression on local" | |
198 | log_must eval "check_prop_source $dest '$userprop:dest' '$userval' local" | |
199 | # Cleanup | |
200 | log_must zfs destroy -r -f $orig | |
201 | log_must zfs destroy -r -f $dest | |
202 | ||
203 | # | |
204 | # 3.3 Verify -o property=value and -x work on both native and user properties | |
205 | # for an incremental replication send stream. | |
206 | # | |
207 | # Create a dataset tree and receive it | |
208 | log_must zfs create $orig | |
209 | log_must zfs create $origsub | |
210 | log_must zfs snapshot -r $orig@snap1 | |
211 | log_must eval "zfs send -R $orig@snap1 > $streamfile_repl" | |
212 | log_must eval "zfs recv $dest < $streamfile_repl" | |
213 | # Fill the datasets with properties and create an incremental replication stream | |
214 | log_must zfs snapshot -r $orig@snap2 | |
215 | log_must eval "zfs set copies=2 $orig" | |
216 | log_must eval "zfs set '$userprop:orig'='$userval' $orig" | |
217 | log_must eval "zfs set '$userprop:orig'='$userval' $origsub" | |
218 | log_must eval "zfs set '$userprop:snap'='$userval' $orig@snap1" | |
219 | log_must eval "zfs set '$userprop:snap'='$userval' $origsub@snap2" | |
220 | log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" | |
221 | # Sets various combination of override and exclude options | |
222 | log_must eval "zfs recv -F -o atime=off -o '$userprop:dest2'='$userval' "\ | |
223 | "-o quota=123456789 -x compression -x '$userprop:orig' " \ | |
224 | "-x '$userprop:snap2' $dest < $streamfile_incr" | |
225 | # Verify we can correctly override and exclude properties | |
226 | log_must eval "check_prop_source $dest copies 2 received" | |
227 | log_must eval "check_prop_source $dest atime off local" | |
228 | log_must eval "check_prop_source $dest '$userprop:dest2' '$userval' local" | |
229 | log_must eval "check_prop_source $dest quota 123456789 local" | |
230 | log_must eval "check_prop_inherit $destsub copies $dest" | |
231 | log_must eval "check_prop_inherit $destsub atime $dest" | |
232 | log_must eval "check_prop_inherit $destsub '$userprop:dest2' $dest" | |
233 | log_must eval "check_prop_source $destsub quota 0 default" | |
234 | log_must eval "check_prop_source $destsub compression off default" | |
235 | log_must eval "check_prop_missing $dest '$userprop:orig'" | |
236 | log_must eval "check_prop_missing $destsub '$userprop:orig'" | |
237 | log_must eval "check_prop_source " \ | |
238 | "$dest@snap1 '$userprop:snap' '$userval' received" | |
239 | log_must eval "check_prop_source " \ | |
240 | "$destsub@snap2 '$userprop:snap' '$userval' received" | |
241 | log_must eval "check_prop_missing $dest@snap2 '$userprop:snap2'" | |
242 | log_must eval "check_prop_missing $destsub@snap2 '$userprop:snap2'" | |
243 | # Cleanup | |
244 | log_must zfs destroy -r -f $orig | |
245 | log_must zfs destroy -r -f $dest | |
246 | ||
247 | # | |
248 | # 3.4 Verify '-x property' does not remove existing local properties and a | |
249 | # modified sent property is received and updated to the new value but can | |
250 | # still be excluded. | |
251 | # | |
252 | # Create a dataset tree | |
253 | log_must zfs create $orig | |
254 | log_must zfs create $origsub | |
255 | log_must zfs snapshot -r $orig@snap1 | |
256 | log_must eval "zfs set copies=2 $orig" | |
257 | log_must eval "zfs set '$userprop:orig'='oldval' $orig" | |
258 | log_must eval "zfs set '$userprop:orig'='oldsubval' $origsub" | |
259 | log_must eval "zfs send -R $orig@snap1 > $streamfile_repl" | |
260 | log_must eval "zfs receive $dest < $streamfile_repl" | |
261 | log_must eval "check_prop_source $dest copies 2 received" | |
262 | log_must eval "check_prop_inherit $destsub copies $dest" | |
263 | log_must eval "check_prop_source $dest '$userprop:orig' 'oldval' received" | |
264 | log_must eval "check_prop_source $destsub '$userprop:orig' 'oldsubval' received" | |
265 | # Set new custom properties on both source and destination | |
266 | log_must eval "zfs set copies=3 $orig" | |
267 | log_must eval "zfs set '$userprop:orig'='newval' $orig" | |
268 | log_must eval "zfs set '$userprop:orig'='newsubval' $origsub" | |
269 | log_must eval "zfs set compression=gzip $dest" | |
270 | log_must eval "zfs set '$userprop:dest'='localval' $dest" | |
271 | # Receive the new stream, verify we preserve locally set properties | |
272 | log_must zfs snapshot -r $orig@snap2 | |
273 | log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" | |
274 | log_must eval "zfs recv -F -x copies -x compression -x '$userprop:orig' " \ | |
275 | "-x '$userprop:dest' $dest < $streamfile_incr" | |
276 | log_must eval "check_prop_source $dest '$userprop:dest' 'localval' local" | |
277 | log_must eval "check_prop_received $dest '$userprop:orig' 'newval'" | |
278 | log_must eval "check_prop_received $destsub '$userprop:orig' 'newsubval'" | |
279 | log_must eval "check_prop_missing $dest '$userprop:orig'" | |
280 | log_must eval "check_prop_missing $destsub '$userprop:orig'" | |
281 | log_must eval "check_prop_source $dest copies 1 default" | |
282 | log_must eval "check_prop_received $dest copies 3" | |
283 | log_must eval "check_prop_source $destsub copies 1 default" | |
284 | log_must eval "check_prop_received $destsub copies '-'" | |
285 | log_must eval "check_prop_source $dest compression gzip local" | |
286 | log_must eval "check_prop_inherit $destsub compression $dest" | |
287 | # Cleanup | |
288 | log_must zfs destroy -r -f $orig | |
289 | log_must zfs destroy -r -f $dest | |
290 | ||
291 | # | |
292 | # 3.5 Verify we can exclude non-inheritable properties from a send stream | |
293 | # | |
294 | # Create a dataset tree and replication stream | |
295 | log_must zfs create $orig | |
296 | log_must zfs create $origsub | |
297 | log_must zfs snapshot -r $orig@snap1 | |
298 | log_must eval "zfs set quota=123456789 $orig" | |
299 | log_must eval "zfs send -R $orig@snap1 > $streamfile_repl" | |
300 | # Receive the stream excluding non-inheritable properties | |
301 | log_must eval "zfs recv -F -x quota $dest < $streamfile_repl" | |
302 | log_must eval "check_prop_source $dest quota 0 default" | |
303 | log_must eval "check_prop_source $destsub quota 0 default" | |
304 | # Set some non-inheritable properties on the destination, verify we keep them | |
305 | log_must eval "zfs set quota=123456789 $dest" | |
306 | log_must eval "zfs set canmount=off $destsub" | |
307 | log_must zfs snapshot -r $orig@snap2 | |
308 | log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" | |
309 | log_must eval "zfs recv -F -x quota -x canmount $dest < $streamfile_incr" | |
310 | log_must eval "check_prop_source $dest quota 123456789 local" | |
311 | log_must eval "check_prop_source $destsub quota 0 default" | |
312 | log_must eval "check_prop_source $destsub canmount off local" | |
313 | # Cleanup | |
314 | log_must zfs destroy -r -f $orig | |
315 | log_must zfs destroy -r -f $dest | |
316 | ||
317 | # | |
318 | # 3.6 Verify we correctly restore existing properties on a failed receive | |
319 | # | |
320 | # Receive a "clean" dataset tree | |
321 | log_must zfs create $orig | |
322 | log_must zfs create $origsub | |
323 | log_must zfs snapshot -r $orig@snap1 | |
324 | log_must eval "zfs send -R $orig@snap1 > $streamfile_repl" | |
325 | log_must eval "zfs receive $dest < $streamfile_repl" | |
326 | # Set custom properties on the destination | |
327 | log_must eval "zfs set atime=off $dest" | |
328 | log_must eval "zfs set quota=123456789 $dest" | |
329 | log_must eval "zfs set '$userprop:orig'='$userval' $dest" | |
330 | log_must eval "zfs set '$userprop:origsub'='$userval' $destsub" | |
331 | # Create a truncated incremental replication stream | |
332 | mntpnt=$(get_prop mountpoint $orig) | |
333 | log_must eval "dd if=/dev/urandom of=$mntpnt/file bs=1024k count=10" | |
334 | log_must zfs snapshot -r $orig@snap2 | |
335 | log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" | |
336 | log_must eval "dd if=$streamfile_incr of=$streamfile_trun bs=1024k count=9" | |
337 | # Receive the truncated stream, verify original properties are kept | |
338 | log_mustnot eval "zfs recv -F -o copies=3 -o quota=987654321 "\ | |
339 | "-o '$userprop:new'='badval' $dest < $streamfile_trun" | |
340 | log_must eval "check_prop_source $dest copies 1 default" | |
341 | log_must eval "check_prop_source $destsub copies 1 default" | |
342 | log_must eval "check_prop_source $dest atime off local" | |
343 | log_must eval "check_prop_inherit $destsub atime $dest" | |
344 | log_must eval "check_prop_source $dest quota 123456789 local" | |
345 | log_must eval "check_prop_source $destsub quota 0 default" | |
346 | log_must eval "check_prop_source $dest '$userprop:orig' '$userval' local" | |
347 | log_must eval "check_prop_inherit $destsub '$userprop:orig' $dest" | |
348 | log_must eval "check_prop_source $destsub '$userprop:origsub' '$userval' local" | |
349 | log_must eval "check_prop_missing $dest '$userprop:new'" | |
350 | # Cleanup | |
351 | log_must zfs destroy -r -f $orig | |
352 | log_must zfs destroy -r -f $dest | |
353 | ||
354 | # | |
355 | # 3.7 Verify we can't receive a send stream overriding or excluding properties | |
356 | # invalid for the dataset type unless the stream it's recursive, in which | |
357 | # case only the appropriate properties are set on the destination. | |
358 | # | |
359 | log_must zfs create -V 128K -s $orig | |
360 | log_must zfs snapshot $orig@snap1 | |
361 | log_must eval "zfs send $orig@snap1 > $streamfile_full" | |
362 | log_mustnot eval "zfs receive -x atime $dest < $streamfile_full" | |
363 | log_mustnot eval "zfs receive -o atime=off $dest < $streamfile_full" | |
364 | log_must zfs destroy -r -f $orig | |
365 | log_must zfs create $orig | |
366 | log_must zfs create -V 128K -s $origsub | |
367 | log_must zfs snapshot -r $orig@snap1 | |
368 | log_must eval "zfs send -R $orig@snap1 > $streamfile_repl" | |
369 | log_must eval "zfs receive -o atime=off $dest < $streamfile_repl" | |
370 | log_must eval "check_prop_source $dest type filesystem -" | |
371 | log_must eval "check_prop_source $dest atime off local" | |
372 | log_must eval "check_prop_source $destsub type volume -" | |
373 | log_must eval "check_prop_source $destsub atime - -" | |
047218e2 AX |
374 | # Cleanup |
375 | log_must zfs destroy -r -f $orig | |
376 | log_must zfs destroy -r -f $dest | |
377 | ||
378 | # | |
379 | # 3.8 Verify 'zfs recv -x|-o' works correctly when used in conjunction with -d | |
380 | # and -e options. | |
381 | # | |
382 | log_must zfs create -p $orig/1/2/3/4 | |
383 | log_must eval "zfs set copies=2 $orig" | |
384 | log_must eval "zfs set atime=on $orig" | |
385 | log_must eval "zfs set '$userprop:orig'='oldval' $orig" | |
386 | log_must zfs snapshot -r $orig@snap1 | |
387 | log_must eval "zfs send -R $orig/1/2@snap1 > $streamfile_repl" | |
388 | # Verify 'zfs recv -e' | |
389 | log_must zfs create $dest | |
390 | log_must eval "zfs receive -e -o copies=3 -x atime "\ | |
391 | "-o '$userprop:orig'='newval' $dest < $streamfile_repl" | |
392 | log_must datasetexists $dest/2/3/4 | |
393 | log_must eval "check_prop_source $dest/2 copies 3 local" | |
394 | log_must eval "check_prop_inherit $dest/2/3/4 copies $dest/2" | |
395 | log_must eval "check_prop_source $dest/2/3/4 atime on default" | |
396 | log_must eval "check_prop_source $dest/2 '$userprop:orig' 'newval' local" | |
397 | log_must eval "check_prop_inherit $dest/2/3/4 '$userprop:orig' $dest/2" | |
398 | log_must zfs destroy -r -f $dest | |
399 | # Verify 'zfs recv -d' | |
400 | log_must zfs create $dest | |
401 | typeset fs="$(echo $orig | awk -F'/' '{print $NF}')" | |
402 | log_must eval "zfs receive -d -o copies=3 -x atime "\ | |
403 | "-o '$userprop:orig'='newval' $dest < $streamfile_repl" | |
404 | log_must datasetexists $dest/$fs/1/2/3/4 | |
405 | log_must eval "check_prop_source $dest/$fs/1/2 copies 3 local" | |
406 | log_must eval "check_prop_inherit $dest/$fs/1/2/3/4 copies $dest/$fs/1/2" | |
407 | log_must eval "check_prop_source $dest/$fs/1/2/3/4 atime on default" | |
408 | log_must eval "check_prop_source $dest/$fs/1/2 '$userprop:orig' 'newval' local" | |
409 | log_must eval "check_prop_inherit $dest/$fs/1/2/3/4 '$userprop:orig' $dest/$fs/1/2" | |
cae5b340 AX |
410 | # We don't need to cleanup here |
411 | ||
412 | log_pass "ZFS receive property override and exclude options passed." |