diff options
Diffstat (limited to 'usr/src/test/smartos-test/smartos-test.sh')
| -rwxr-xr-x | usr/src/test/smartos-test/smartos-test.sh | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/usr/src/test/smartos-test/smartos-test.sh b/usr/src/test/smartos-test/smartos-test.sh new file mode 100755 index 0000000000..d3bc4d1840 --- /dev/null +++ b/usr/src/test/smartos-test/smartos-test.sh @@ -0,0 +1,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 |
