diff --git a/.travis.yml b/.travis.yml index 4aab4f73..5926cd95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,10 +13,6 @@ os: language: bash -env: - - AGENT_INIT=no - - AGENT_INIT=yes - services: - docker diff --git a/Makefile b/Makefile index cca78ed2..d57a7828 100644 --- a/Makefile +++ b/Makefile @@ -3,59 +3,87 @@ # # SPDX-License-Identifier: Apache-2.0 # -MK_DIR :=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) - -DISTRO ?= centos -DISTRO_ROOTFS := $(PWD)/$(DISTRO)_rootfs -DISTRO_ROOTFS_MARKER := .$(shell basename $(DISTRO_ROOTFS)).done -IMAGE := kata-containers.img -INITRD_IMAGE := kata-containers-initrd.img -IMG_SIZE=500 -AGENT_INIT ?= no - -VERSION_FILE := ./VERSION -VERSION := $(shell grep -v ^\# $(VERSION_FILE)) -COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true) -COMMIT := $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO}) +MK_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +TEST_RUNNER := $(MK_DIR)/tests/test_images.sh +ROOTFS_BUILDER := $(MK_DIR)/rootfs-builder/rootfs.sh +INITRD_BUILDER := $(MK_DIR)/initrd-builder/initrd_builder.sh +IMAGE_BUILDER := $(MK_DIR)/image-builder/image_builder.sh + +IMG_SIZE = 500 +AGENT_INIT ?= no +DISTRO ?= centos +ROOTFS_BUILD_DEST := $(PWD) +IMAGES_BUILD_DEST := $(PWD) +DISTRO_ROOTFS := $(ROOTFS_BUILD_DEST)/$(DISTRO)_rootfs +DISTRO_ROOTFS_MARKER := $(ROOTFS_BUILD_DEST)/.$(DISTRO)_rootfs.done +DISTRO_IMAGE := $(IMAGES_BUILD_DEST)/kata-containers.img +DISTRO_INITRD := $(IMAGES_BUILD_DEST)/kata-containers-initrd.img + +VERSION_FILE := ./VERSION +VERSION := $(shell grep -v ^\# $(VERSION_FILE)) +COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true) +COMMIT := $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO}) VERSION_COMMIT := $(if $(COMMIT),$(VERSION)-$(COMMIT),$(VERSION)) +################################################################################ + +rootfs-%: $(ROOTFS_BUILD_DEST)/.%_rootfs.done + @ # DONT remove. This is not cancellation rule. + +.PRECIOUS: $(ROOTFS_BUILD_DEST)/.%_rootfs.done +$(ROOTFS_BUILD_DEST)/.%_rootfs.done:: rootfs-builder/% + @echo Creating rootfs for "$*" + $(ROOTFS_BUILDER) -o $(VERSION_COMMIT) -r $(ROOTFS_BUILD_DEST)/$*_rootfs $* + touch $@ + +image-%: $(IMAGES_BUILD_DEST)/kata-containers-image-%.img + @ # DONT remove. This is not cancellation rule. + +.PRECIOUS: $(IMAGES_BUILD_DEST)/kata-containers-image-%.img +$(IMAGES_BUILD_DEST)/kata-containers-image-%.img: rootfs-% + @echo Creating image based on $^ + $(IMAGE_BUILDER) -s $(IMG_SIZE) -o $@ $(ROOTFS_BUILD_DEST)/$*_rootfs + +initrd-%: $(IMAGES_BUILD_DEST)/kata-containers-initrd-%.img + @ # DONT remove. This is not cancellation rule. + +.PRECIOUS: $(IMAGES_BUILD_DEST)/kata-containers-initrd-%.img +$(IMAGES_BUILD_DEST)/kata-containers-initrd-%.img: rootfs-% + @echo Creating initrd image for $* + $(INITRD_BUILDER) -o $@ $(ROOTFS_BUILD_DEST)/$*_rootfs + .PHONY: all all: image initrd .PHONY: rootfs rootfs: $(DISTRO_ROOTFS_MARKER) -$(DISTRO_ROOTFS_MARKER): - @echo Creating rootfs based on "$(DISTRO)" - "$(MK_DIR)/rootfs-builder/rootfs.sh" -o $(VERSION_COMMIT) -r $(DISTRO_ROOTFS) $(DISTRO) - touch $@ - .PHONY: image -image: $(IMAGE) +image: $(DISTRO_IMAGE) -$(IMAGE): rootfs +$(DISTRO_IMAGE): $(DISTRO_ROOTFS_MARKER) @echo Creating image based on "$(DISTRO_ROOTFS)" - "$(MK_DIR)/image-builder/image_builder.sh" -s "$(IMG_SIZE)" "$(DISTRO_ROOTFS)" + $(IMAGE_BUILDER) -s "$(IMG_SIZE)" "$(DISTRO_ROOTFS)" .PHONY: initrd -initrd: $(INITRD_IMAGE) +initrd: $(DISTRO_INITRD) -$(INITRD_IMAGE): rootfs +$(DISTRO_INITRD): $(DISTRO_ROOTFS_MARKER) @echo Creating initrd image based on "$(DISTRO_ROOTFS)" - "$(MK_DIR)/initrd-builder/initrd_builder.sh" "$(DISTRO_ROOTFS)" + $(INITRD_BUILDER) "$(DISTRO_ROOTFS)" .PHONY: test test: - "$(MK_DIR)/tests/test_images.sh" "$(DISTRO)" + $(TEST_RUNNER) "$(DISTRO)" .PHONY: test-image-only test-image-only: - "$(MK_DIR)/tests/test_images.sh" --test-images-only "$(DISTRO)" + $(TEST_RUNNER) --test-images-only "$(DISTRO)" .PHONY: test-initrd-only test-initrd-only: - "$(MK_DIR)/tests/test_images.sh" --test-initrds-only "$(DISTRO)" + $(TEST_RUNNER) --test-initrds-only "$(DISTRO)" .PHONY: clean clean: - rm -rf $(DISTRO_ROOTFS_MARKER) $(DISTRO_ROOTFS) $(IMAGE) $(INITRD_IMAGE) + rm -rf $(DISTRO_ROOTFS_MARKER) $(DISTRO_ROOTFS) $(DISTRO_IMAGE) $(DISTRO_INITRD) diff --git a/rootfs-builder/rootfs.sh b/rootfs-builder/rootfs.sh index 0659d4a1..05e22a96 100755 --- a/rootfs-builder/rootfs.sh +++ b/rootfs-builder/rootfs.sh @@ -52,8 +52,8 @@ $(get_distros) Refer the Platform-OS Compatibility Matrix: https://github.com/kata-containers/osbuilder#platform-distro-compatibility-matrix Options: --a : agent version DEFAULT: ${AGENT_VERSION} ENV: AGENT_VERSION --h : Show this help message +-a : agent version DEFAULT: ${AGENT_VERSION} ENV: AGENT_VERSION +-h : show this help message -o : specify version of osbuilder -r : rootfs directory DEFAULT: ${ROOTFS_DIR} ENV: ROOTFS_DIR @@ -90,7 +90,7 @@ distro_needs_admin_caps() then echo "true" elif [ "$1" = "debian" ] - then + then echo "true" else echo "false" diff --git a/tests/test_config.sh b/tests/test_config.sh new file mode 100644 index 00000000..ffa9b1ac --- /dev/null +++ b/tests/test_config.sh @@ -0,0 +1,17 @@ +# +# Copyright (c) 2018 SUSE LLC +# +# SPDX-License-Identifier: Apache-2.0 + +distrosSystemd=(fedora centos ubuntu debian) +distrosAgent=(alpine) + +if [ $MACHINE_TYPE != "ppc64le" ]; then + distrosSystemd+=(clearlinux) +fi + +# "Not testing eurleros on Travis: (timeout, see: https://github.com/kata-containers/osbuilder/issues/46)" +if [ -z "${TRAVIS:-}" ]; then + distrosSystemd+=(euleros) +fi + diff --git a/tests/test_images.sh b/tests/test_images.sh index 194970ed..6d305d1e 100755 --- a/tests/test_images.sh +++ b/tests/test_images.sh @@ -4,20 +4,17 @@ # # SPDX-License-Identifier: Apache-2.0 -set -e +set -euo pipefail readonly script_dir="$(dirname $(readlink -f $0))" readonly script_name=${0##*/} - -readonly rootfs_sh="${script_dir}/../rootfs-builder/rootfs.sh" -readonly image_builder_sh="${script_dir}/../image-builder/image_builder.sh" -readonly initrd_builder_sh="${script_dir}/../initrd-builder/initrd_builder.sh" readonly tmp_dir=$(mktemp -t -d osbuilder-test.XXXXXXX) readonly tmp_rootfs="${tmp_dir}/rootfs-osbuilder" readonly images_dir="${tmp_dir}/images" readonly osbuilder_file="/var/lib/osbuilder/osbuilder.yaml" readonly docker_image="busybox" -readonly docker_config_file="/etc/systemd/system/docker.service.d/kata-containers.conf" +readonly systemd_docker_config_file="/etc/systemd/system/docker.service.d/kata-containers.conf" +readonly sysconfig_docker_config_file="/etc/sysconfig/docker" readonly tests_repo="github.com/kata-containers/tests" readonly tests_repo_dir="${script_dir}/../../tests" readonly mgr="${tests_repo_dir}/cmd/kata-manager/kata-manager.sh" @@ -30,8 +27,10 @@ readonly test_func_prefix="test_distro_" # "docker build" does not work with a VM-based runtime readonly docker_build_runtime="runc" -test_images_only="false" -test_initrds_only="false" +build_images=1 +build_initrds=1 + +source ${script_dir}/test_config.sh # Hashes used to keep track of image sizes. # - Key: name of distro. @@ -138,14 +137,15 @@ exit_handler() rm -rf "${tmp_dir}" + # Restore the default image in config file + [ -n "${TRAVIS:-}" ] || chronic $mgr configure-image + return fi info "ERROR: test failed" # The test failed so dump what we can - info "AGENT_INIT: '${AGENT_INIT}'" - info "images:" sudo -E ls -l "${images_dir}" >&2 @@ -163,6 +163,9 @@ exit_handler() info "processes:" sudo -E ps -efwww | egrep "docker|kata" >&2 + + # Restore the default image in config file + [ -n "${TRAVIS:-}" ] || chronic $mgr configure-image } die() @@ -185,7 +188,15 @@ set_runtime() [ -z "$name" ] && die "need name" # Travis doesn't support VT-x - [ -n "$TRAVIS" ] && return + [ -n "${TRAVIS:-}" ] && return + + source /etc/os-release + + if [[ "${ID_LIKE:-}" =~ suse ]]; then + docker_config_file="$sysconfig_docker_config_file" + else + docker_config_file="$systemd_docker_config_file" + fi sudo -E sed -i "s/--default-runtime=[^ ][^ ]*/--default-runtime=${name}/g" \ "${docker_config_file}" @@ -201,7 +212,7 @@ setup() export USE_DOCKER=true # Travis doesn't support VT-x - [ -n "$TRAVIS" ] && return + [ -n "${TRAVIS:-}" ] && return [ ! -d "${tests_repo_dir}" ] && git clone "https://${tests_repo}" "${tests_repo_dir}" @@ -212,56 +223,6 @@ setup() set_runtime "${docker_build_runtime}" } -build_rootfs() -{ - local distro="$1" - local rootfs="$2" - - [ -z "$distro" ] && die "need distro" - [ -z "$rootfs" ] && die "need rootfs" - - local full="${rootfs}${osbuilder_file}" - - # clean up from any previous runs - [ -d "${rootfs}" ] && sudo -E rm -rf "${rootfs}" - - sudo -E ${rootfs_sh} -r "${rootfs}" "${distro}" - - yamllint "${full}" - - info "built rootfs for distro '$distro' at '$rootfs'" - info "osbuilder metadata file:" - cat "${full}" >&2 -} - -build_image() -{ - local file="$1" - local rootfs="$2" - - [ -z "$file" ] && die "need file" - [ -z "$rootfs" ] && die "need rootfs" - - sudo -E ${image_builder_sh} -o "${file}" "${rootfs}" - - info "built image file '$file' for rootfs '$rootfs':" - sudo -E ls -l "$file" >&2 -} - -build_initrd() -{ - local file="$1" - local rootfs="$2" - - [ -z "$file" ] && die "need file" - [ -z "$rootfs" ] && die "need rootfs" - - sudo -E ${initrd_builder_sh} -o "${file}" "${rootfs}" - - info "built initrd file '$file' for rootfs '$rootfs':" - sudo -E ls -l "$file" >&2 -} - create_container() { out=$(mktemp) @@ -287,7 +248,7 @@ install_image_create_container() [ ! -e "$file" ] && die "file does not exist: $file" # Travis doesn't support VT-x - [ -n "$TRAVIS" ] && return + [ -n "${TRAVIS:-}" ] && return chronic $mgr reset-config chronic $mgr configure-image "$file" @@ -302,246 +263,192 @@ install_initrd_create_container() [ ! -e "$file" ] && die "file does not exist: $file" # Travis doesn't support VT-x - [ -n "$TRAVIS" ] && return + [ -n "${TRAVIS:-}" ] && return chronic $mgr reset-config chronic $mgr configure-initrd "$file" create_container } -handle_options() +# Displays a list of distros which can be tested +list_distros() { - local distro="$1" - local type="$2" - local options="$3" - - [ -z "$distro" ] && die "need distro" - [ -z "$type" ] && die "need type" - - local opt - local rootfs - - for opt in $options - do - # Set the crucial variable to determine if the agent will be - # PID 1 in the image or initrd. - case "$opt" in - init) export AGENT_INIT="yes";; - *) export AGENT_INIT="no";; - esac - - rootfs="${tmp_rootfs}/${distro}-agent-init-${AGENT_INIT}" + tr " " "\n" <<< "${distrosSystemd[@]} ${distrosAgent[@]}" | sort +} - build_rootfs "${distro}" "${rootfs}" +# +# Calls the `GNU make` utility with the set of passed arguments. +# Arguments can either be make targets or make variables assignments (in the form of VARIABLE=) +# +call_make() { + targetType=$1 + shift + makeVars=() + makeTargets=() + # Split args between make variable and targets + for t in $@; do + # RE to match a make variable assignment + pattern="^\w+\=" + if [[ "$t" =~ $pattern ]]; then + makeVars+=("$t") + else + makeTargets+=($targetType-$t) + fi + done - local rootfs_size=$(du -sb "${rootfs}" | awk '{print $1}') + makeJobs= + if [ -z "${CI:-}" ]; then + ((makeJobs=$(nproc) / 2)) + fi - if [ "$type" = "image" ] - then - # Images need systemd - [ "$opt" = "init" ] && continue + info "Starting make with \n\ + # of // jobs: ${makeJobs:-[unlimited]} \n\ + targets: ${makeTargets[@]} \n\ + variables: ${makeVars[@]}" - local image_path="${images_dir}/${type}-${distro}-agent-init-${AGENT_INIT}.img" + sudo -E make -j $makeJobs ${makeTargets[@]} ${makeVars[@]} +} - build_image "${image_path}" "${rootfs}" - local image_size=$(stat -c "%s" "${image_path}") +make_rootfs() { + call_make rootfs $@ +} - built_images["${distro}"]="${rootfs_size}:${image_size}" +make_image() { + call_make image $@ +} - install_image_create_container "${image_path}" - elif [ "$type" = "initrd" ] - then - local initrd_path="${images_dir}/${type}-${distro}-agent-init-${AGENT_INIT}.img" +make_initrd() { + call_make initrd $@ +} - build_initrd "${initrd_path}" "${rootfs}" - local initrd_size=$(stat -c "%s" "${initrd_path}") +get_rootfs_size() { + [ $# -ne 1 ] && die "get_rootfs_size with wrong invalid argument" - built_initrds["${distro}"]="${rootfs_size}:${initrd_size}" + local rootfs_dir=$1 + ! [ -d "$rootfs_dir" ] && die "$rootfs_dir is not a valid rootfs path" - install_initrd_create_container "${initrd_path}" - else - die "invalid type: '$type' for distro $distro option $opt" - fi - done + sudo -E du -sb "${rootfs_dir}" | awk '{print $1}' } -# Create an image and/or initrd for the specified distribution, +# Create an image and/or initrd for the available distributions, # then test each by configuring the runtime and creating a container. # -# The second and third parameters take the form of a space separated list of -# values which represent whether the agent should be the init daemon in the -# image/initrd. "init" means the agent should be configured to be the init -# daemon and "service" means it should run as a systemd service. -# -# The list value should be set to "no" if the image/initrd should not -# be built+tested. +# When passing the name of a distribution, tests are run against that +# distribution only. # # Parameters: # # 1: distro name. -# 2: image options. -# 3: initrd options. -create_and_run() +# +test_distros() { local distro="$1" - local image_options="$2" - local initrd_options="$3" - - [ -z "$distro" ] && die "need distro" - [ -z "$image_options" ] && die "need image options" - [ -z "$initrd_options" ] && die "need initrd options" - - local opt - - if [ "$image_options" != "no" ] - then - if [ "${test_initrds_only}" = "true" ] - then - info "only testing initrds: skipping image test for distro $distro" - else - handle_options "$distro" "image" "$image_options" - fi - fi - - if [ "$initrd_options" != "no" ] - then - if [ "${test_images_only}" = "true" ] - then - info "only testing images: skipping initrd test for distro $distro" + local separator="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + echo -e "$separator" + + # If a distro was specified, filter out the distro list to only include that distro + if [ -n "$distro" ]; then + pattern="\<$distro\>" + if [[ "${distrosAgent[@]}" =~ $pattern ]]; then + distrosAgent=($distro) + distrosSystemd=() + elif [[ "${distrosSystemd[@]}" =~ $pattern ]]; then + distrosSystemd=($distro) + distrosAgent=() + build_initrds= else - handle_options "$distro" "initrd" "$initrd_options" + die "Not a valid distro: $distro" fi - fi -} - -run_test() -{ - local -r name="$1" - local -r skip="$2" - local -r distro="$3" - local -r image_options="$4" - local -r initrd_options="$5" - - [ -z "$name" ] && die "need name" - [ -z "$distro" ] && die "need distro" - [ -z "$image_options" ] && die "need image options" - [ -z "$initrd_options" ] && die "need initrd options" - - [ -n "$skip" ] && info "Skipping test $name: $skip" && return - - info "Running test: ${name}" - create_and_run "${distro}" "${image_options}" "${initrd_options}" -} - -test_distro_ubuntu() -{ - local -r name="Can create and run ubuntu image" - run_test "${name}" "" "ubuntu" "service" "no" -} - -test_distro_debian() -{ - local -r name="Can create and run debian image" - run_test "${name}" "" "debian" "service" "no" -} - - -test_distro_fedora() -{ - local -r name="Can create and run fedora image" - run_test "${name}" "" "fedora" "service" "no" -} - -test_distro_clearlinux() -{ - local -r name="Can create and run clearlinux image" - - run_test "${name}" "" "clearlinux" "service" "no" -} + info "Running tests for distro: $distro" -test_distro_centos() -{ - local -r name="Can create and run centos image" - run_test "${name}" "" "centos" "service" "no" -} + else + info "Running tests for all distros" + fi -test_distro_euleros() -{ - local -r name="Can create and run euleros image" + # distro with systemd as init -> normal rootfs image + # distro with kata-agent as init -> normal rootfs image AND initrd image - [ "$TRAVIS" = true ] && skip="travis timeout, see: https://github.com/kata-containers/osbuilder/issues/46" + # If user does not need rootfs images, then do not build systemd rootfses + [ -z "$build_images" ] && distrosSystemd=() - run_test "${name}" "$skip" "euleros" "service" "no" -} + commonMakeVars=( \ + USE_DOCKER=true \ + ROOTFS_BUILD_DEST="$tmp_rootfs" \ + IMAGES_BUILD_DEST="$images_dir" ) -test_distro_alpine() -{ - local -r name="Can create and run alpine image" - run_test "${name}" "" "alpine" "no" "init" -} + # Build systemd and agent rootfs with 2 separate jobs + bgJobs=() -# Displays a list of all distro test functions -get_distro_test_names() -{ - typeset -F | awk '{print $3}' |\ - grep "^${test_func_prefix}" | sort -} + if [ ${#distrosSystemd[@]} -gt 0 ]; then + info "building rootfses with systemd as init: ${distrosSystemd[@]}" + make_rootfs ${commonMakeVars[@]} "${distrosSystemd[@]}" & + bgJobs+=($!) + fi -# Displays a list of distros which can be tested -list_distros() -{ - get_distro_test_names | sed "s/${test_func_prefix}//g" -} + if [ ${#distrosAgent[@]} -gt 0 ]; then + info "building all rootfses with kata-agent as init" + make_rootfs ${commonMakeVars[@]} AGENT_INIT=yes "${distrosAgent[@]}" & + bgJobs+=($!) + fi -test_single_distro() -{ - local -r distro="$1" + # Check for build failures (`wait` remembers up to CHILD_MAX bg processes exit status) + for j in ${bgJobs[@]}; do + wait $j || die "Background build job failed" + done - [ -z "$distro" ] && die "distro cannot be blank" - local -r expected_func="${test_func_prefix}${distro}" + for d in ${distrosSystemd[@]} ${distrosAgent[@]}; do + local rootfs_path="${tmp_rootfs}/${d}_rootfs" + osbuilder_file_fullpath="${rootfs_path}/${osbuilder_file}" + echo -e "$separator" + yamllint "${osbuilder_file_fullpath}" - local test_funcs - test_funcs=$(get_distro_test_names) + info "osbuilder metadata file for $d:" + cat "${osbuilder_file_fullpath}" >&2 + done - local defined_func - defined_func=$(echo "$test_funcs" | grep "^${expected_func}$" || true) - if [ -z "$defined_func" ] - then - local distros + # TODO: once support for rootfs images with kata-agent as init is in place, + # uncomment the following line +# for d in ${distrosSystemd[@]} ${distrosAgent[@]}; do + for d in ${distrosSystemd[@]}; do + local rootfs_path="${tmp_rootfs}/${d}_rootfs" + local image_path="${images_dir}/kata-containers-image-$d.img" + local rootfs_size=$(get_rootfs_size "$rootfs_path") - # make a comma-separated list - distros=$(list_distros | tr '\n' ',' | sed 's/,$//g') + echo -e "$separator" + info "Making rootfs image for ${d}" + make_image ${commonMakeVars[@]} $d + local image_size=$(stat -c "%s" "${image_path}") - die "no test for distro '$distro' (try one of $distros)" - fi + echo -e "$separator" + built_images["${d}"]="${rootfs_size}:${image_size}" + info "Creating container for ${d}" + install_image_create_container $image_path + done - info "only running tests for distro $distro" + for d in ${distrosAgent[@]}; do + local rootfs_path="${tmp_rootfs}/${d}_rootfs" + local initrd_path="${images_dir}/kata-containers-initrd-$d.img" + local rootfs_size=$(get_rootfs_size "$rootfs_path") - # run the test - $defined_func -} + echo -e "$separator" + info "Making initrd image for ${d}" + make_initrd ${commonMakeVars[@]} AGENT_INIT=yes $d + local initrd_size=$(stat -c "%s" "${initrd_path}") -test_all_distros() -{ - info "running tests for all distros" - - test_distro_fedora - test_distro_centos - test_distro_alpine - test_distro_ubuntu - test_distro_debian - if [ $MACHINE_TYPE != "ppc64le" ]; then - test_distro_clearlinux - - # Run last as EulerOS servers can be slow and we don't want to fail the - # previous tests. - test_distro_euleros - fi + echo -e "$separator" + built_initrds["${d}"]="${rootfs_size}:${initrd_size}" + info "Creating container for ${d}" + install_initrd_create_container $initrd_path + done + echo -e "$separator" show_stats + + echo -e "$separator" } main() @@ -566,13 +473,11 @@ main() --list) list_distros; exit 0;; --test-images-only) - test_images_only="true" - test_initrds_only="false" + build_initrds= ;; --test-initrds-only) - test_initrds_only="true" - test_images_only="false" + build_images= ;; --) shift; break ;; @@ -584,21 +489,16 @@ main() # Consume getopt cruft [ "$1" = "--" ] && shift - case "$1" in + case "${1:-}" in help) usage; exit 0;; - *) distro="$1";; + *) distro="${1:-}";; esac trap exit_handler EXIT ERR setup - if [ -n "$distro" ] - then - test_single_distro "$distro" - else - test_all_distros - fi + test_distros "$distro" # We shouldn't really need a message like this but the CI can fail in # mysterious ways so make it clear!