#!/bin/bash set -e USAGE="USAGE: $(basename "$0") [run|edit] " GOSS_FILES_PATH="${GOSS_FILES_PATH:-.}" # Container runtime CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}" info() { echo -e "INFO: $*" >&2; } error() { echo -e "ERROR: $*" >&2; exit 1; } cleanup() { set +e { kill "$log_pid" && wait "$log_pid"; } 2> /dev/null if [ -n "$CONTAINER_LOG_OUTPUT" ]; then cp "$tmp_dir/docker_output.log" "$CONTAINER_LOG_OUTPUT" fi rm -rf "$tmp_dir" if [[ $id ]];then info "Deleting container" $CONTAINER_RUNTIME rm -vf "$id" > /dev/null fi } run(){ # Copy in goss cp "${GOSS_PATH}" "$tmp_dir/goss" chmod 755 "$tmp_dir/goss" [[ -e "${GOSS_FILES_PATH}/${GOSS_FILE:-goss.yaml}" ]] && cp "${GOSS_FILES_PATH}/${GOSS_FILE:-goss.yaml}" "$tmp_dir/goss.yaml" && chmod 644 "$tmp_dir/goss.yaml" [[ -e "${GOSS_FILES_PATH}/goss_wait.yaml" ]] && cp "${GOSS_FILES_PATH}/goss_wait.yaml" "$tmp_dir" && chmod 644 "$tmp_dir/goss_wait.yaml" [[ -n "${GOSS_VARS}" ]] && [[ -e "${GOSS_FILES_PATH}/${GOSS_VARS}" ]] && cp "${GOSS_FILES_PATH}/${GOSS_VARS}" "$tmp_dir" && chmod 644 "$tmp_dir/${GOSS_VARS}" # Switch between mount or cp files strategy GOSS_FILES_STRATEGY=${GOSS_FILES_STRATEGY:="mount"} case "$GOSS_FILES_STRATEGY" in mount) info "Starting $CONTAINER_RUNTIME container" if [ "$CONTAINER_RUNTIME" == "podman" -a $# == 2 ]; then id=$($CONTAINER_RUNTIME run -d -v "$tmp_dir:/goss:z" "${@:2}" sleep infinity) else id=$($CONTAINER_RUNTIME run -d -v "$tmp_dir:/goss:z" "${@:2}") fi ;; cp) info "Creating $CONTAINER_RUNTIME container" id=$($CONTAINER_RUNTIME create "${@:2}") info "Copy goss files into container" $CONTAINER_RUNTIME cp "$tmp_dir/." "$id:/goss" info "Starting $CONTAINER_RUNTIME container" $CONTAINER_RUNTIME start "$id" > /dev/null ;; *) error "Wrong goss files strategy used! Correct options are \"mount\" or \"cp\"." esac $CONTAINER_RUNTIME logs -f "$id" > "$tmp_dir/docker_output.log" 2>&1 & log_pid=$! info "Container ID: ${id:0:8}" } get_docker_file() { local cid=$1 # Docker container ID local src=$2 # Source file path (in the container) local dst=$3 # Destination file path if $CONTAINER_RUNTIME exec "${cid}" sh -c "test -e ${src}" > /dev/null; then mkdir -p "${GOSS_FILES_PATH}" $CONTAINER_RUNTIME cp "${cid}:${src}" "${dst}" info "Copied '${src}' from container to '${dst}'" fi } # Main tmp_dir=$(mktemp -d ${DGOSS_TEMP_DIR:-/tmp}/tmp.XXXXXXXXXX) chmod 777 "$tmp_dir" trap 'ret=$?;cleanup;exit $ret' EXIT GOSS_PATH="${GOSS_PATH:-$(which goss 2> /dev/null || true)}" [[ $GOSS_PATH ]] || { error "Couldn't find goss installation, please set GOSS_PATH to it"; } [[ ${GOSS_OPTS+x} ]] || GOSS_OPTS="--color --format documentation" [[ ${GOSS_WAIT_OPTS+x} ]] || GOSS_WAIT_OPTS="-r 30s -s 1s > /dev/null" GOSS_SLEEP=${GOSS_SLEEP:-0.2} [[ $CONTAINER_RUNTIME =~ ^(docker|podman)$ ]] || { error "Runtime must be one of docker or podman"; } case "$1" in run) run "$@" if [[ -e "${GOSS_FILES_PATH}/goss_wait.yaml" ]]; then info "Found goss_wait.yaml, waiting for it to pass before running tests" if [[ -z "${GOSS_VARS}" ]]; then if ! $CONTAINER_RUNTIME exec "$id" sh -c "/goss/goss -g /goss/goss_wait.yaml validate $GOSS_WAIT_OPTS"; then $CONTAINER_RUNTIME logs "$id" >&2 error "goss_wait.yaml never passed" fi else if ! $CONTAINER_RUNTIME exec "$id" sh -c "/goss/goss -g /goss/goss_wait.yaml --vars='/goss/${GOSS_VARS}' validate $GOSS_WAIT_OPTS"; then $CONTAINER_RUNTIME logs "$id" >&2 error "goss_wait.yaml never passed" fi fi fi [[ $GOSS_SLEEP ]] && { info "Sleeping for $GOSS_SLEEP"; sleep "$GOSS_SLEEP"; } info "Container health" if [ "true" != "$($CONTAINER_RUNTIME inspect -f '{{.State.Running}}' "$id")" ]; then $CONTAINER_RUNTIME logs "$id" >&2 error "the container failed to start" fi info "Running Tests" if [[ -z "${GOSS_VARS}" ]]; then $CONTAINER_RUNTIME exec "$id" sh -c "/goss/goss -g /goss/goss.yaml validate $GOSS_OPTS" else $CONTAINER_RUNTIME exec "$id" sh -c "/goss/goss -g /goss/goss.yaml --vars='/goss/${GOSS_VARS}' validate $GOSS_OPTS" fi ;; edit) run "$@" info "Run goss add/autoadd to add resources" $CONTAINER_RUNTIME exec -it "$id" sh -c 'cd /goss; PATH="/goss:$PATH" exec sh' get_docker_file "$id" "/goss/goss.yaml" "${GOSS_FILES_PATH}/${GOSS_FILE:-goss.yaml}" get_docker_file "$id" "/goss/goss_wait.yaml" "${GOSS_FILES_PATH}/goss_wait.yaml" if [[ -n "${GOSS_VARS}" ]]; then get_docker_file "$id" "/goss/${GOSS_VARS}" "${GOSS_FILES_PATH}/${GOSS_VARS}" fi ;; *) error "$USAGE" esac