1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
|
#! /usr/bin/bash
#
#
# 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.
#
#
# This script is designed to run on an (effectively) disposable SmartOS
# install to configure the system, install a series of tests from the
# smartos-gate, and execute them.
# It exits 1 if any configuration, setup or test fails.
#
export PATH=/usr/bin:/usr/sbin:/opt/tools/sbin:/opt/tools/bin:$PATH
# The pkgsrc packages we will install.
export SMARTOS_TEST_PKGS="
python27
sudo
coreutils
gcc7
gmake
"
#
# Set $KEEP as a precaution in case we ever end up running the zfs-test suite
# by accident or design. This ensures it never attempts to destroy the 'zones'
# zpool. Note that the ZFS test suite also wants DISKS set to the disks which
# it can create/destroy pools on, but we're not computing that here.
#
if [[ -z "$KEEP" ]]; then
export KEEP="zones"
fi
#
# Accumulate test suite exit codes and a list of failed tests
#
RESULT=0
FAILED_TESTS=""
function fatal {
echo "ERROR: $@"
exit 1
}
function warn {
echo "WARNING: $@"
}
function log {
echo "$@"
}
function log_must {
echo "Running $@"
$@ || fatal "Error running command."
}
function log_test {
echo ""
TEST_NAME=$1
shift
echo "Starting test for $TEST_NAME with $@"
$@
TEST_RESULT=$?
if [[ $TEST_RESULT -ne 0 ]]; then
FAILED_TESTS="$FAILED_TESTS $TEST_NAME"
fi
RESULT=$(( $RESULT + $TEST_RESULT ))
}
function log_testrunner {
echo ""
TEST_NAME=$1
shift
echo "Starting test-runner for $TEST_NAME with $@"
/opt/test-runner/bin/run -c $@
TEST_RESULT=$?
if [[ $TEST_RESULT -ne 0 ]]; then
FAILED_TESTS="$FAILED_TESTS $TEST_NAME"
fi
RESULT=$(( $RESULT + $TEST_RESULT ))
# test-runner's default log dirs use a timestamp at per-second granularity.
# Sleep here to ensure a unique timestamp per run if consecutive tests
# bail out early.
sleep 1
}
function guard_production_data {
if [[ ! -f "/lib/sdc/.sdc-test-no-production-data" ]]; then
cat <<EOF
To setup and run these tests you must create the file:
/lib/sdc/.sdc-test-no-production-data
after ensuring you have no production data on this system.
EOF
exit 1
fi
}
function zone_check {
if [[ $(zonename) != "global" ]]; then
fatal "these tests must be run from the global zone."
fi
}
#
# Check that the tests.buildstamp file in the test archive matches
# the current platform stamp. Running tests designed for a platform
# that we're not running is a bad idea.
#
function version_check {
PLATFORM_VERSION=$(uname -v | sed -e 's/^joyent_//g')
mkdir -p /tmp/version_check.$$
tar xzf $1 -C /tmp/version_check.$$ ./tests.buildstamp
TESTS_VERSION=$(cat /tmp/version_check.$$/tests.buildstamp)
rm -rf /tmp/version_check.$$
log "Platform version: $PLATFORM_VERSION"
log " Tests version: $TESTS_VERSION"
if [[ "$PLATFORM_VERSION" != "$TESTS_VERSION" ]]; then
fatal "mismatched platform version and tests version!"
fi
}
function snapshot_rollback_opt {
snapshot="system-test-smartos-test"
has_snapshot=$(zfs list zones/opt@$snapshot 2> /dev/null)
if [[ -n "$has_snapshot" ]]; then
log_must zfs rollback zones/opt@$snapshot
else
log_must zfs snapshot zones/opt@$snapshot
fi
}
#
# Since some tests want to deliver to /usr which is read-only on SmartOS,
# we make a temporary directory, dump the current /usr there, extract our
# content to it, then lofs-mount it over the real thing.
#
function add_loopback_mounts {
test_archive=$1
lofs_home=/var/tmp/smartos-test-loopback
# If /usr is already lofs mounted, and pointing at $lofs_home, just
# extract our new test bits on top. Ideally we'd just unmount it,
# but while running this script, there's a good chance that the dataset
# will be busy and the umount would fail.
FS=$(/bin/df -n /usr | awk '{print $NF'})
if [[ "$FS" == "lofs" ]]; then
is_test_lofs=$(mount | grep ^/usr | grep "$lofs_home/usr ")
if [[ -z "$is_test_lofs" ]]; then
fatal "unsupported: existing lofs mount for /usr is not $lofs_home"
else
log "Extracting new test archive to lofs-mounted /usr"
# extract the current test archive to it
log_must tar -xzf $test_archive -C $lofs_home ./usr
fi
# Otherwise, setup a lofs mount for it.
else
log "Creating new lofs mount for /usr on $lofs_home"
rm -rf $lofs_home
mkdir -p $lofs_home
find /usr | cpio -pdum $lofs_home
log_must tar -xzf $test_archive -C $lofs_home ./usr
# keep /usr read-only in an attempt to preserve smartos behaviour
# unless specifically asked to
if [[ "$mount_usr_rw" = "true" ]]; then
mount_opts="-o rw"
else
mount_opts="-o ro"
fi
log_must mount -O -F lofs $mount_opts $lofs_home/usr /usr
fi
}
#
# Extract the non-/usr parts of the test archive
#
function extract_remaining_test_bits {
log_must tar -xzf $1 -C / \
./opt ./kernel ./tests.manifest.gen ./tests.buildstamp
}
function setup_pkgsrc {
if [[ -f /opt/tools/etc/pkgin/repositories.conf ]]; then
log "Pkgsrc bootstrap already setup, continuing"
return
fi
# We should always use the same pkgsrc version as we have installed
# on the build machine in case any of our tests link against libraries
# in /opt/local
PKGSRC_STEM="https://pkgsrc.joyent.com/packages/SmartOS/bootstrap"
BOOTSTRAP_TAR="bootstrap-2018Q4-tools.tar.gz"
BOOTSTRAP_SHA="b599667c80e4a42157763ed25d868ec7dc34962d"
# Ensure we are in a directory with enough space for the bootstrap
# download, by default the SmartOS /root directory is limited to the size
# of the ramdisk.
cd /var/tmp
# Download the bootstrap kit to the current directory. Note that we
# currently pass "-k" to skip SSL certificate checks as the GZ doesn't
# install them.
log_must curl -kO ${PKGSRC_STEM}/${BOOTSTRAP_TAR}
# Verify the SHA1 checksum.
[[ "${BOOTSTRAP_SHA}" = "$(/bin/digest -a sha1 ${BOOTSTRAP_TAR})" ]] || \
fatal "checksum failure for ${BOOTSTRAP_TAR}, expected ${BOOTSTRAP_SHA}"
# Install bootstrap kit to /opt/tools
log_must tar -zxpf ${BOOTSTRAP_TAR} -C /
# add a symlink from /opt/local, needed by many test suites
if [[ ! -d /opt/local && ! -L /opt/local ]]; then
log_must ln -s /opt/tools /opt/local
else
log "Not forging /opt/local link"
fi
}
function install_required_pkgs {
log_must pkgin -y in ${SMARTOS_TEST_PKGS}
}
function add_test_accounts {
grep -q cyrus: /etc/passwd
if [[ $? -ne 0 ]]; then
log "Adding cyrus user"
echo "cyrus:x:977:1::/zones/global/cyrus:/bin/sh" >> /etc/passwd
echo "cyrus:*LK*:::::::" >> /etc/shadow
mkdir -p /zones/global/cyrus
chown cyrus /zones/global/cyrus
fi
grep -q ztest: /etc/passwd
if [[ $? -ne 0 ]]; then
log "Adding ztest user"
echo "ztest:x:978:1::/zones/global/ztest:/bin/sh" >> /etc/passwd
echo "ztest:*LK*:::::::" >> /etc/shadow
mkdir -p /zones/global/ztest
chown ztest /zones/global/ztest
fi
if [[ ! -f /opt/tools/etc/sudoers.d/ztest ]]; then
mkdir -p /opt/tools/etc/sudoers.d
echo "ztest ALL=(ALL) NOPASSWD: ALL" >> /opt/tools/etc/sudoers.d/ztest
fi
}
#
# By using log_test or log_testrunner, we accumulate the exit codes from each
# test run to $RESULT.
#
# We don't - yet - run net-tests, smbclient-tests, zfs-tests, or the dtrace
# suite.
#
function execute_tests {
log "Starting test runs"
log_test bhyvetest /opt/bhyvetest/bin/bhyvetest -ak
log_testrunner crypto-tests /opt/crypto-tests/runfiles/default.run
log_testrunner elf-tests /opt/elf-tests/runfiles/default.run
log_testrunner libc-tests /opt/libc-tests/runfiles/default.run
log_test vndtest /opt/vndtest/bin/vndtest -a
log_testrunner util-tests /opt/util-tests/runfiles/default.run
log_testrunner os-tests /opt/os-tests/runfiles/default.run
if [[ -n "$FAILED_TESTS" ]]; then
echo ""
log "Failures were seen in the following test suites: $FAILED_TESTS"
fi
}
function usage {
echo "Usage: smartos-test [-h] [-c] [-e] [-r] [-w] <path to tests.tgz>"
echo ""
echo "At least one of -c, -e, -r is required."
echo ""
echo " -h print usage"
echo " -c configure the system for testing"
echo " -e execute known tests"
echo " -f skip the check to ensure platform version == test version"
echo " -r snapshot or rollback to zones/opt@system-test-smartos-test"
echo " before doing any system configuration or test execution"
echo " -w when mounting the lofs /usr, make it writable"
}
mount_usr_rw=false
skip_version_check=false
do_configure=false
do_execute=false
do_rollback=false
#
# Main
#
while getopts "cefrwh" opt; do
case "${opt}" in
c)
do_configure=true
;;
e)
do_execute=true
;;
f)
skip_version_check=true
;;
r)
do_rollback=true
;;
h)
usage
exit 2
;;
w)
mount_usr_rw=true
;;
*)
log "unknown argument ${opt}"
usage
exit 2
esac
done
shift $((OPTIND - 1))
test_archive=$1
if [[ -z "$test_archive" ]]; then
log "missing test archive argument."
usage
exit 1
fi
if [[ ! -f "$test_archive" ]]; then
usage
fatal "unable to access test archive at $test_archive"
fi
if [[ "$do_rollback" = false && \
"$do_configure" = false && \
"$do_execute" = false ]]; then
log "nothing to do: use at least one of -r -e -c"
usage
exit 2
fi
if [[ "$skip_version_check" = false ]]; then
version_check $1
fi
guard_production_data
zone_check
if [[ $do_rollback = true ]]; then
snapshot_rollback_opt
fi
if [[ $do_configure = true ]]; then
add_loopback_mounts $test_archive
extract_remaining_test_bits $test_archive
add_test_accounts
setup_pkgsrc
install_required_pkgs
log "This system is now configured to run the SmartOS tests."
fi
if [[ "$do_execute" = true ]]; then
execute_tests
fi
if [[ $RESULT -gt 0 ]]; then
exit 1
else
exit 0
fi
|