df396a
#!/bin/bash
c5011b
c5011b
# Script to test the openSUSE infrastructure Salt code in a local container
c5011b
# Copyright (C) 2017-2024 openSUSE contributors
c5011b
#
c5011b
# This program is free software: you can redistribute it and/or modify
c5011b
# it under the terms of the GNU General Public License as published by
c5011b
# the Free Software Foundation, either version 3 of the License, or
c5011b
# (at your option) any later version.
c5011b
#
c5011b
# This program is distributed in the hope that it will be useful,
c5011b
# but WITHOUT ANY WARRANTY; without even the implied warranty of
c5011b
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
c5011b
# GNU General Public License for more details.
c5011b
#
c5011b
# You should have received a copy of the GNU General Public License
c5011b
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
Theo Chatzimichos 96429a
Theo Chatzimichos 96429a
help() {
c5011b
    echo 'Run tests on your workstation.'
c5011b
    echo 'Do NOT run this as root.'
Theo Chatzimichos 96429a
    echo
Theo Chatzimichos 96429a
    echo "Arguments:"
c5011b
    echo '-h - Print this text.'
c5011b
    echo
c5011b
    echo '-c - Use the specified existing container instead of instantiating a new one.'
c5011b
    echo '-k - Path to a public SSH key to use for authentication. If not specified, an insecure key will be used.'
c5011b
    echo '-p - Preserve container after tests finished running.'
b748c8
    echo '-s - Test full highstates. This takes a lot of time!'
Theo Chatzimichos 96429a
    echo
Theo Chatzimichos 96429a
}
Theo Chatzimichos 96429a
c5011b
print() {
c5011b
    printf '==> %s\n' "$1"
c5011b
}
c5011b
c5011b
pprint() {
df396a
    printf '==> %s %s ...\n' "$1" "$(gum style --foreground \#96cb5c "$2")"
c5011b
}
c5011b
c5011b
fail() {
c5011b
    echo "$1"
c5011b
    exit 1
c5011b
}
c5011b
c5011b
pfail() {
c5011b
    printf '! %s\n' "$(gum style --foreground \#d11137 FAILED)"
c5011b
    exit 1
c5011b
}
Theo Chatzimichos 96429a
df396a
[ "$(id -u)" = 0 ] && help && exit 1
df396a
[ "$1" = '--help' ] && help && exit
Theo Chatzimichos 96429a
c5011b
CONTAINER=''
c5011b
CONTAINER_ARGS=()
c5011b
SSH_ARGS=( '-t' '-oStrictHostKeyChecking=no' '-oUserKnownHostsFile=/dev/null' '-oLogLevel=ERROR' '-lchecker' )
c5011b
PRESERVE=false
b748c8
HIGHSTATE=false
c5011b
b748c8
while getopts h:c:k:p:s arg; do
c5011b
    case "$arg" in
Theo Chatzimichos 96429a
        h) help && exit ;;
c5011b
        c) CONTAINER="${OPTARG}" ;;
c5011b
        k) PUBKEY=${OPTARG} ;;
c5011b
        p) CONTAINER_ARGS+=('--rm') ; PRESERVE=true ;;
b748c8
        s) HIGHSTATE=true ;;
Theo Chatzimichos 96429a
        *) help && exit 1 ;;
Theo Chatzimichos 96429a
    esac
Theo Chatzimichos 96429a
done
Theo Chatzimichos 96429a
c5011b
print 'Pre-flight check ...'
c215e0
test -f encrypted_pillar_recipients || fail 'Please run this script from the salt.git repository root.'
c5011b
command -v podman >/dev/null || fail 'Please install Podman first.'
c5011b
command -v ssh >/dev/null || fail 'Please install the OpenSSH client first.'
c5011b
command -v rsync >/dev/null || fail 'Please install rsync first.'
c5011b
getent hosts ipv6-localhost >/dev/null || fail 'Please ensure ipv6-localhost maps to ::1 (default on openSUSE).'
c5011b
if [ -z "$PUBKEY" ] || ! file -bL "$PUBKEY" | grep -q 'OpenSSH .* public key'
c5011b
then
c5011b
    fail 'Please provide a public OpenSSH key using -k.'
c5011b
fi
Theo Chatzimichos 96429a
c5011b
set -Cu
Theo Chatzimichos 96429a
c5011b
if [ -z "$CONTAINER" ]
c5011b
then
c5011b
    print 'Pulling container ...'
c5011b
    podman pull -q registry.opensuse.org/opensuse/infrastructure/containers/heroes-salt-development-systemd \
c5011b
      || fail 'Failed to pull container'
c5011b
    
c5011b
    print 'Preparing ...'
c5011b
    PORT=2222
c5011b
    while [ -n "$(ss -Htlno state listening sport = $PORT)" ]
c5011b
    do
c5011b
      PORT=$((PORT+1))
c5011b
    done
c5011b
    echo "$PORT"
c5011b
    
c5011b
    print 'Starting ...'
c5011b
    CONTAINER=$( \
df396a
      podman run -de SSH_KEY="$(cat "$PUBKEY")" --health-interval 10s --health-start-period 15s "${CONTAINER_ARGS[@]}" -p "[::1]:$PORT:22" -v .:/home/geeko/salt-workspace:ro \
c5011b
      registry.opensuse.org/opensuse/infrastructure/containers/heroes-salt-development-systemd:latest \
c5011b
    )
c5011b
    timeout 90 podman wait --condition healthy "$CONTAINER" >/dev/null \
c5011b
      || fail 'Failed to start container'
c5011b
    podman logs "$CONTAINER"
c5011b
else
c5011b
    print "Preparing container $CONTAINER ..."
c5011b
    set -e
df396a
    podman ps | grep -q "$CONTAINER" || podman start "$CONTAINER"
c5011b
    timeout 60 podman wait --condition healthy "$CONTAINER" >/dev/null \
c5011b
      || fail 'Failed to start container'
df396a
    PORT="$(podman inspect -f '{{(index (index .NetworkSettings.Ports "22/tcp") 0).HostPort}}' "$CONTAINER" || echo null)"
df396a
    if [ "$PORT" = 'null' ] || ! podman ps | grep -q "$CONTAINER"
c5011b
    then
c5011b
        fail 'Cannot work with the specified container.'
c5011b
    fi
c5011b
    podman exec "$CONTAINER" test -f /var/adm/firstboot-ok || fail 'Existing container was not set up correctly or does not use the expected image.'
df396a
    podman exec "$CONTAINER" sh -c "echo $(cat "$PUBKEY") >> /home/checker/.ssh/authorized_keys"
c5011b
    set +e
c5011b
fi
c5011b
c5011b
SSH_ARGS+=("-p$PORT")
df396a
SSH="ssh ${SSH_ARGS[*]}"
c5011b
RSYNC_ARGS=('-l' '-r' '-e' "$SSH")
c5011b
SSH="$SSH ipv6-localhost"
c5011b
c5011b
$SSH true || fail 'Container connection failed.'
c5011b
$SSH sudo install -do checker /srv/salt-formulas /srv/salt-testbed || fail 'Failed to create directories.'
c5011b
c5011b
rsync "${RSYNC_ARGS[@]}" . ipv6-localhost:/srv/salt-testbed || fail 'Failed to transfer repository.'
c5011b
c5011b
$SSH sh <<-EOS || echo 'Test suite returned with errors.'
c5011b
  $(typeset -f pprint)
c5011b
  $(typeset -f pfail)
c5011b
  pushd /srv/salt-testbed >/dev/null
c5011b
c5011b
  pprint 'Preparing test environment'
c5011b
  sudo bin/prepare_test_env.sh -g -s || pfail
b748c8
  sudo sed -i 's/download-prg.infra.opensuse.org/download.opensuse.org/' /etc/zypp/repos.d/*
c5011b
c5011b
  pprint Testing: validate
c5011b
  bin/test_validate.sh || pfail
c5011b
c5011b
  pprint Testing: show_highstate
c5011b
  sudo bin/test_show_highstate.sh || pfail
c5011b
df396a
  if [ "$HIGHSTATE" = 'true' ]
b748c8
  then
b748c8
    pprint Testing: highstate
b748c8
    sudo bin/test_highstate.sh
b748c8
  fi
b748c8
c5011b
  popd >/dev/null
c5011b
  pprint 'All tests' completed
c5011b
EOS
c5011b
df396a
if [ "$PRESERVE" = 'false' ]
c5011b
then
c5011b
  print 'Removing container ...'
c5011b
  podman stop "$CONTAINER" >/dev/null || fail 'Failed to stop container.'
c5011b
  podman rm "$CONTAINER" >/dev/null || fail 'Failed to remove container.'
c5011b
fi
c5011b
c5011b
echo Bye.