2 # SPDX-License-Identifier: BSD-2-Clause
4 # Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 ZPOOL_NAME_FILE=zpool_name
36 mktemp -u bectl_test_XXXXXX > $ZPOOL_NAME_FILE
40 # Establishes a bectl_create zpool that can be used for some light testing; contains
41 # a 'default' BE and not much else.
48 # Sanity check to make sure `make_zpool_name` succeeded
49 atf_check test -n "$zpool"
51 kldload -n -q zfs || atf_skip "ZFS module not loaded on the current system"
52 if ! getconf MIN_HOLE_SIZE "$(pwd)"; then
53 echo "getconf MIN_HOLE_SIZE $(pwd) failed; sparse files " \
54 "probably not supported by file system"
56 atf_skip "Test's work directory does not support sparse files;" \
57 "try with a different TMPDIR?"
59 atf_check mkdir -p ${mnt}
60 atf_check truncate -s 1G ${disk}
61 atf_check zpool create -R ${mnt} ${zpool} ${disk}
62 atf_check zfs create -o mountpoint=none ${zpool}/ROOT
63 atf_check zfs create -o mountpoint=/ -o canmount=noauto \
66 bectl_create_deep_setup()
72 # Sanity check to make sure `make_zpool_name` succeeded
73 atf_check test -n "$zpool"
75 bectl_create_setup ${zpool} ${disk} ${mnt}
76 atf_check mkdir -p ${root}
77 atf_check -o ignore bectl -r ${zpool}/ROOT mount default ${root}
78 atf_check mkdir -p ${root}/usr
79 atf_check zfs create -o mountpoint=/usr -o canmount=noauto \
80 ${zpool}/ROOT/default/usr
81 atf_check -o ignore bectl -r ${zpool}/ROOT umount default
87 if [ -z "$zpool" ]; then
88 echo "Skipping cleanup; zpool not set up"
89 elif zpool get health ${zpool} >/dev/null 2>&1; then
90 zpool destroy -f ${zpool}
94 atf_test_case bectl_create cleanup
98 atf_set "descr" "Check the various forms of bectl create"
99 atf_set "require.user" root
103 if [ "$(atf_config_get ci false)" = "true" ] && \
104 [ "$(uname -p)" = "i386" ]; then
105 atf_skip "https://bugs.freebsd.org/249055"
108 if [ "$(atf_config_get ci false)" = "true" ] && \
109 [ "$(uname -p)" = "armv7" ]; then
110 atf_skip "https://bugs.freebsd.org/249229"
114 zpool=$(make_zpool_name)
118 bectl_create_setup ${zpool} ${disk} ${mount}
120 # Create a child dataset that will be used to test creation
121 # of recursive and non-recursive boot environments.
122 atf_check zfs create -o mountpoint=/usr -o canmount=noauto \
123 ${zpool}/ROOT/default/usr
125 # BE datasets with spaces are not bootable, PR 254441.
126 atf_check -e not-empty -s not-exit:0 \
127 bectl -r ${zpool}/ROOT create "foo bar"
129 # Test standard creation, creation of a snapshot, and creation from a
131 atf_check bectl -r ${zpool}/ROOT create -e default default2
132 atf_check bectl -r ${zpool}/ROOT create default2@test_snap
133 atf_check bectl -r ${zpool}/ROOT create -e default2@test_snap default3
135 # Test standard creation, creation of a snapshot, and creation from a
136 # snapshot for recursive boot environments.
137 atf_check bectl -r ${zpool}/ROOT create -r -e default recursive
138 atf_check bectl -r ${zpool}/ROOT create -r recursive@test_snap
139 atf_check bectl -r ${zpool}/ROOT create -r -e recursive@test_snap recursive-snap
141 # Test that non-recursive boot environments have no child datasets.
142 atf_check -e not-empty -s not-exit:0 \
143 zfs list "${zpool}/ROOT/default2/usr"
144 atf_check -e not-empty -s not-exit:0 \
145 zfs list "${zpool}/ROOT/default3/usr"
147 # Test that recursive boot environments have child datasets.
148 atf_check -o not-empty \
149 zfs list "${zpool}/ROOT/recursive/usr"
150 atf_check -o not-empty \
151 zfs list "${zpool}/ROOT/recursive-snap/usr"
153 bectl_create_cleanup()
155 bectl_cleanup $(get_zpool_name)
158 atf_test_case bectl_destroy cleanup
162 atf_set "descr" "Check bectl destroy"
163 atf_set "require.user" root
167 if [ "$(atf_config_get ci false)" = "true" ] && \
168 [ "$(uname -p)" = "i386" ]; then
169 atf_skip "https://bugs.freebsd.org/249055"
172 if [ "$(atf_config_get ci false)" = "true" ] && \
173 [ "$(uname -p)" = "armv7" ]; then
174 atf_skip "https://bugs.freebsd.org/249229"
178 zpool=$(make_zpool_name)
183 bectl_create_setup ${zpool} ${disk} ${mount}
184 atf_check bectl -r ${zpool}/ROOT create -e default default2
185 atf_check -o not-empty zfs get mountpoint ${zpool}/ROOT/default2
186 atf_check -e ignore bectl -r ${zpool}/ROOT destroy default2
187 atf_check -e not-empty -s not-exit:0 zfs get mountpoint ${zpool}/ROOT/default2
189 # Test origin snapshot deletion when the snapshot to be destroyed
190 # belongs to a mounted dataset, see PR 236043.
191 atf_check mkdir -p ${root}
192 atf_check -o not-empty bectl -r ${zpool}/ROOT mount default ${root}
193 atf_check bectl -r ${zpool}/ROOT create -e default default3
194 atf_check bectl -r ${zpool}/ROOT destroy -o default3
195 atf_check bectl -r ${zpool}/ROOT unmount default
197 # create two be from the same parent and destroy the parent
198 atf_check bectl -r ${zpool}/ROOT create -e default default2
199 atf_check bectl -r ${zpool}/ROOT create -e default default3
200 atf_check bectl -r ${zpool}/ROOT destroy default
201 atf_check bectl -r ${zpool}/ROOT destroy default2
202 atf_check bectl -r ${zpool}/ROOT rename default3 default
204 # Create a BE, have it be the parent for another and repeat, then start
205 # deleting environments. Arbitrarily chose default3 as the first.
206 # Sleeps are required to prevent conflicting snapshots- libbe will
207 # use the time with a serial at the end as needed to prevent collisions,
208 # but as BEs get promoted the snapshot names will convert and conflict
209 # anyways. libbe should perhaps consider adding something extra to the
210 # default name to prevent collisions like this, but the default name
211 # includes down to the second and creating BEs this rapidly is perhaps
213 atf_check bectl -r ${zpool}/ROOT create -e default default2
215 atf_check bectl -r ${zpool}/ROOT create -e default2 default3
217 atf_check bectl -r ${zpool}/ROOT create -e default3 default4
218 atf_check bectl -r ${zpool}/ROOT destroy default3
219 atf_check bectl -r ${zpool}/ROOT destroy default2
220 atf_check bectl -r ${zpool}/ROOT destroy default4
222 # Create two BEs, then create an unrelated snapshot on the originating
223 # BE and destroy it. We shouldn't have promoted the second BE, and it's
224 # only possible to tell if we promoted it by making sure we didn't
225 # demote the first BE at some point -- if we did, it's origin will no
227 atf_check bectl -r ${zpool}/ROOT create -e default default2
228 atf_check bectl -r ${zpool}/ROOT create default@test
230 atf_check bectl -r ${zpool}/ROOT destroy default@test
231 atf_check -o inline:"-\n" zfs get -Ho value origin ${zpool}/ROOT/default
232 atf_check bectl -r ${zpool}/ROOT destroy default2
234 # As observed by beadm, if we explicitly try to destroy a snapshot that
235 # leads to clones, we shouldn't have allowed it.
236 atf_check bectl -r ${zpool}/ROOT create default@test
237 atf_check bectl -r ${zpool}/ROOT create -e default@test default2
239 atf_check -e not-empty -s not-exit:0 bectl -r ${zpool}/ROOT destroy \
242 bectl_destroy_cleanup()
245 bectl_cleanup $(get_zpool_name)
248 atf_test_case bectl_export_import cleanup
249 bectl_export_import_head()
252 atf_set "descr" "Check bectl export and import"
253 atf_set "require.user" root
255 bectl_export_import_body()
257 if [ "$(atf_config_get ci false)" = "true" ] && \
258 [ "$(uname -p)" = "i386" ]; then
259 atf_skip "https://bugs.freebsd.org/249055"
262 if [ "$(atf_config_get ci false)" = "true" ] && \
263 [ "$(uname -p)" = "armv7" ]; then
264 atf_skip "https://bugs.freebsd.org/249229"
268 zpool=$(make_zpool_name)
272 bectl_create_setup ${zpool} ${disk} ${mount}
273 atf_check -o save:exported bectl -r ${zpool}/ROOT export default
274 atf_check -x "bectl -r ${zpool}/ROOT import default2 < exported"
275 atf_check -o not-empty zfs get mountpoint ${zpool}/ROOT/default2
276 atf_check -e ignore bectl -r ${zpool}/ROOT destroy default2
277 atf_check -e not-empty -s not-exit:0 zfs get mountpoint \
278 ${zpool}/ROOT/default2
280 bectl_export_import_cleanup()
283 bectl_cleanup $(get_zpool_name)
286 atf_test_case bectl_list cleanup
290 atf_set "descr" "Check bectl list"
291 atf_set "require.user" root
295 if [ "$(atf_config_get ci false)" = "true" ] && \
296 [ "$(uname -p)" = "i386" ]; then
297 atf_skip "https://bugs.freebsd.org/249055"
300 if [ "$(atf_config_get ci false)" = "true" ] && \
301 [ "$(uname -p)" = "armv7" ]; then
302 atf_skip "https://bugs.freebsd.org/249229"
306 zpool=$(make_zpool_name)
310 bectl_create_setup ${zpool} ${disk} ${mount}
311 # Test the list functionality, including that BEs come and go away
312 # as they're created and destroyed. Creation and destruction tests
313 # use the 'zfs' utility to verify that they're actually created, so
314 # these are just light tests that 'list' is picking them up.
315 atf_check -o save:list.out bectl -r ${zpool}/ROOT list
316 atf_check -o not-empty grep 'default' list.out
317 atf_check bectl -r ${zpool}/ROOT create -e default default2
318 atf_check -o save:list.out bectl -r ${zpool}/ROOT list
319 atf_check -o not-empty grep 'default2' list.out
320 atf_check -e ignore bectl -r ${zpool}/ROOT destroy default2
321 atf_check -o save:list.out bectl -r ${zpool}/ROOT list
322 atf_check -s not-exit:0 grep 'default2' list.out
323 # XXX TODO: Formatting checks
328 bectl_cleanup $(get_zpool_name)
331 atf_test_case bectl_mount cleanup
335 atf_set "descr" "Check bectl mount/unmount"
336 atf_set "require.user" root
340 if [ "$(atf_config_get ci false)" = "true" ] && \
341 [ "$(uname -p)" = "i386" ]; then
342 atf_skip "https://bugs.freebsd.org/249055"
345 if [ "$(atf_config_get ci false)" = "true" ] && \
346 [ "$(uname -p)" = "armv7" ]; then
347 atf_skip "https://bugs.freebsd.org/249229"
351 zpool=$(make_zpool_name)
356 bectl_create_deep_setup ${zpool} ${disk} ${mount}
357 atf_check mkdir -p ${root}
358 # Test unmount first...
359 atf_check -o not-empty bectl -r ${zpool}/ROOT mount default ${root}
360 atf_check -o not-empty -x "mount | grep '^${zpool}/ROOT/default'"
361 atf_check bectl -r ${zpool}/ROOT unmount default
362 atf_check -s not-exit:0 -x "mount | grep '^${zpool}/ROOT/default'"
364 atf_check -o not-empty bectl -r ${zpool}/ROOT mount default ${root}
365 atf_check -o not-empty -x "mount | grep '^${zpool}/ROOT/default'"
366 atf_check bectl -r ${zpool}/ROOT umount default
367 atf_check -s not-exit:0 -x "mount | grep '^${zpool}/ROOT/default'"
369 bectl_mount_cleanup()
372 bectl_cleanup $(get_zpool_name)
375 atf_test_case bectl_rename cleanup
379 atf_set "descr" "Check bectl rename"
380 atf_set "require.user" root
384 if [ "$(atf_config_get ci false)" = "true" ] && \
385 [ "$(uname -p)" = "i386" ]; then
386 atf_skip "https://bugs.freebsd.org/249055"
389 if [ "$(atf_config_get ci false)" = "true" ] && \
390 [ "$(uname -p)" = "armv7" ]; then
391 atf_skip "https://bugs.freebsd.org/249229"
395 zpool=$(make_zpool_name)
399 bectl_create_setup ${zpool} ${disk} ${mount}
400 atf_check bectl -r ${zpool}/ROOT rename default default2
401 atf_check -o not-empty zfs get mountpoint ${zpool}/ROOT/default2
402 atf_check -e not-empty -s not-exit:0 zfs get mountpoint \
403 ${zpool}/ROOT/default
405 bectl_rename_cleanup()
408 bectl_cleanup $(get_zpool_name)
411 atf_test_case bectl_jail cleanup
415 atf_set "descr" "Check bectl rename"
416 atf_set "require.user" root
417 atf_set "require.progs" jail
421 if [ "$(atf_config_get ci false)" = "true" ] && \
422 [ "$(uname -p)" = "i386" ]; then
423 atf_skip "https://bugs.freebsd.org/249055"
426 if [ "$(atf_config_get ci false)" = "true" ] && \
427 [ "$(uname -p)" = "armv7" ]; then
428 atf_skip "https://bugs.freebsd.org/249229"
432 zpool=$(make_zpool_name)
437 if [ ! -f /rescue/rescue ]; then
438 atf_skip "This test requires a rescue binary"
440 bectl_create_deep_setup ${zpool} ${disk} ${mount}
441 # Prepare our minimal BE... plop a rescue binary into it
442 atf_check mkdir -p ${root}
443 atf_check -o ignore bectl -r ${zpool}/ROOT mount default ${root}
444 atf_check mkdir -p ${root}/rescue
445 atf_check cp /rescue/rescue ${root}/rescue/rescue
446 atf_check bectl -r ${zpool}/ROOT umount default
448 # Prepare some more boot environments
449 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT create -e default target
450 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT create -e default 1234
452 # Attempt to unjail a BE with numeric name; jail_getid at one point
453 # did not validate that the input was a valid jid before returning the
455 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b 1234
456 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail 1234
458 # When a jail name is not explicit, it should match the jail id.
459 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b -o jid=233637 default
460 atf_check -o inline:"233637\n" -s exit:0 -x "jls -j 233637 name"
461 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail default
463 # Basic command-mode tests, with and without jail cleanup
464 atf_check -o inline:"rescue\nusr\n" bectl -r ${zpool}/ROOT \
465 jail default /rescue/rescue ls -1
466 atf_check -o inline:"rescue\nusr\n" bectl -r ${zpool}/ROOT \
467 jail -Uo path=${root} default /rescue/rescue ls -1
468 atf_check [ -f ${root}/rescue/rescue ]
469 atf_check bectl -r ${zpool}/ROOT ujail default
472 atf_check bectl -r ${zpool}/ROOT jail -bo path=${root} default
473 atf_check -o not-empty -x "jls | grep -F \"${root}\""
474 atf_check bectl -r ${zpool}/ROOT ujail default
475 atf_check -s not-exit:0 -x "jls | grep -F \"${root}\""
477 atf_check bectl -r ${zpool}/ROOT jail -b default
478 atf_check bectl -r ${zpool}/ROOT unjail default
479 atf_check -s not-exit:0 -x "jls | grep -F \"${root}\""
480 # 'unjail' by BE name. Force bectl to lookup jail id by the BE name.
481 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b default
482 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b -o name=bectl_test target
483 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail target
484 atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail default
485 # cannot unjail an unjailed BE (by either command name)
486 atf_check -e ignore -s not-exit:0 bectl -r ${zpool}/ROOT ujail default
487 atf_check -e ignore -s not-exit:0 bectl -r ${zpool}/ROOT unjail default
490 atf_check bectl -r ${zpool}/ROOT jail -b -o path=${root} -u path default
491 # Ensure that it didn't mount at ${root}
492 atf_check -s not-exit:0 -x "mount | grep -F '${root}'"
493 atf_check bectl -r ${zpool}/ROOT ujail default
496 # If a test has failed, it's possible that the boot environment hasn't
497 # been 'unjail'ed. We want to remove the jail before 'bectl_cleanup'
498 # attempts to destroy the zpool.
501 if [ "$(atf_config_get ci false)" = "true" ] && \
502 [ "$(uname -p)" = "i386" ]; then
503 atf_skip "https://bugs.freebsd.org/249055"
506 if [ "$(atf_config_get ci false)" = "true" ] && \
507 [ "$(uname -p)" = "armv7" ]; then
508 atf_skip "https://bugs.freebsd.org/249229"
511 zpool=$(get_zpool_name)
512 for bootenv in "default" "target" "1234"; do
513 # mountpoint of the boot environment
514 mountpoint="$(bectl -r ${zpool}/ROOT list -H | grep ${bootenv} | awk '{print $3}')"
516 # see if any jail paths match the boot environment mountpoint
517 jailid="$(jls | grep ${mountpoint} | awk '{print $1}')"
519 if [ -z "$jailid" ]; then
525 bectl_cleanup ${zpool}
528 atf_init_test_cases()
530 atf_add_test_case bectl_create
531 atf_add_test_case bectl_destroy
532 atf_add_test_case bectl_export_import
533 atf_add_test_case bectl_list
534 atf_add_test_case bectl_mount
535 atf_add_test_case bectl_rename
536 atf_add_test_case bectl_jail