mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-26 21:33:05 +00:00
utils: Rewrite run-tests.sh to use functions and extenal scripts
To modify Azure tests and depend on shell scripts and pytest instead
of molecule, the run-tests.sh script has been rewritten to depend on
bash functions and on a bash script that prepare and start a testing
container.
This patch adds a new script, 'utils/setup_test_container.sh' that
can be used to start a new container, using either podman or docker,
based on the available ansible-freeipa images. The new container can
then be used to run ansible-freeipa tests against it.
Also the following files with bash functions were added, and are
used by both scripts:
utils/shansible: Functions to run playbooks in the container
utils/shcontainer: Functions to setup/run a container
utils/shfun: Generic shell helper functions (e.g.: log)
This commit is contained in:
committed by
Thomas Woerner
parent
0c6a7c8a14
commit
68bca84481
@@ -1,38 +1,19 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
trap interrupt_exception SIGINT
|
||||
SCRIPTDIR="$(readlink -f "$(dirname "$0")")"
|
||||
TOPDIR="$(readlink -f "${SCRIPTDIR}/..")"
|
||||
|
||||
RST="\033[0m"
|
||||
RED="\033[31m"
|
||||
# BRIGHTRED="\033[31;1m"
|
||||
# GREEN="\033[32m"
|
||||
BRIGHTGREEN="\033[32;1m"
|
||||
# BROWN="\033[33m"
|
||||
YELLOW="\033[33;1m"
|
||||
# NAVY="\033[34m"
|
||||
BLUE="\033[34;1m"
|
||||
# MAGENTA="\033[35m"
|
||||
# BRIGHTMAGENTA="\033[35;1m"
|
||||
# DARKCYAN="\033[36m"
|
||||
# CYAN="\033[36;1m"
|
||||
# BLACK="\033[30m"
|
||||
# DARKGRAY="\033[30;1m"
|
||||
# GRAY="\033[37m"
|
||||
WHITE="\033[37;1m"
|
||||
|
||||
TOPDIR="$(readlink -f "$(dirname "$0")/..")"
|
||||
|
||||
interrupt_exception() {
|
||||
trap - SIGINT
|
||||
log warn "User interrupted test execution."
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
# shellcheck source=utils/shfun
|
||||
. "${SCRIPTDIR}/shfun"
|
||||
# shellcheck source=utils/shcontainer
|
||||
. "${SCRIPTDIR}/shcontainer"
|
||||
# shellcheck source=utils/shansible
|
||||
. "${SCRIPTDIR}/shansible"
|
||||
|
||||
usage() {
|
||||
local prog="${0##*/}"
|
||||
cat <<EOF
|
||||
usage: ${prog} [-h] [-l] [-e] [-K] [-c CONTAINER] [-s TESTS_SUITE] [-x] [-A SEED.GRP] [-i IMAGE] [-m MEMORY] [-v...] [TEST...]
|
||||
usage: ${prog} [-h] [-l] [-e] [-K] [-A|-a ANSIBLE] [-p INTERPRETER] [-c CONTAINER] [-s TESTS_SUITE] [-x] [-S SEED.GRP] [-i IMAGE] [-m MEMORY] [-v...] [TEST...]
|
||||
${prog} runs playbook(s) TEST using an ansible-freeipa testing image.
|
||||
|
||||
EOF
|
||||
@@ -47,172 +28,72 @@ positional arguments:
|
||||
|
||||
optional arguments:
|
||||
-h display this message and exit
|
||||
-a ANSIBLE Ansible version to use, e.g. "ansible-core==2.16.0"
|
||||
(default: latest ansible-core for the python version)
|
||||
-A Do not install Ansible, use host's provided one.
|
||||
-c CONTAINER use container CONTAINER to run tests
|
||||
-K keep container, even if tests succeed
|
||||
-l list available images
|
||||
-e force recreation of the virtual environment
|
||||
-i IMAGE select image to run the tests (default: fedora-latest)
|
||||
-m container memory, in GiB (default: 3)
|
||||
-m MEMORY container memory, in GiB (default: 3)
|
||||
-p INTERPRETER Python interpreter to use on target container
|
||||
-s TEST_SUITE run all playbooks for test suite, which is a directory
|
||||
under ${WHITE}tests${RST}
|
||||
-A SEED.GROUP Replicate Azure's test group and seed (seed is YYYYMMDD)
|
||||
-S SEED.GROUP Replicate Azure's test group and seed (seed is YYYYMMDD)
|
||||
-v Increase Ansible verbosity (can be used multiple times)
|
||||
-x Stop on first error.
|
||||
EOF
|
||||
)"
|
||||
}
|
||||
|
||||
log() {
|
||||
local level="${1^^}" message="${*:2}"
|
||||
case "${level}" in
|
||||
ERROR) COLOR="${RED}" ;;
|
||||
WARN) COLOR="${YELLOW}" ;;
|
||||
DEBUG) COLOR="${BLUE}" ;;
|
||||
INFO) COLOR="${WHITE}" ;;
|
||||
SUCCESS) COLOR="${BRIGHTGREEN}" ;;
|
||||
*) COLOR="${RST}" ;;
|
||||
esac
|
||||
echo -en "${COLOR}"
|
||||
[ "${level}" == "ERROR" ] && echo -en "${level}:"
|
||||
echo -e "${message}${RST}"
|
||||
}
|
||||
|
||||
quiet() {
|
||||
"$@" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
in_python_virtualenv() {
|
||||
local script
|
||||
read -r -d "" script <<EOS
|
||||
import sys;
|
||||
base = getattr(sys, "base_prefix", ) or getattr(sys, "real_prefix", ) or sys.prefix
|
||||
print('yes' if sys.prefix != base else 'no')
|
||||
EOS
|
||||
test "$(python -c "${script}")" == "yes"
|
||||
}
|
||||
|
||||
run_inline_playbook() {
|
||||
local playbook
|
||||
local err
|
||||
quiet mkdir -p "${test_env}/playbooks"
|
||||
playbook=$(mktemp "${test_env}/playbooks/ansible-freeipa-test-playbook_ipa.XXXXXXXX")
|
||||
cat - >"${playbook}"
|
||||
ansible-playbook -i "${inventory}" "${playbook}"
|
||||
err=$?
|
||||
rm "${playbook}"
|
||||
return ${err}
|
||||
}
|
||||
|
||||
die() {
|
||||
usg="N"
|
||||
if [ "${1}" == "-u" ]
|
||||
then
|
||||
usg="Y"
|
||||
shift 1
|
||||
fi
|
||||
log error "${*}"
|
||||
STOP_CONTAINER="N"
|
||||
cleanup
|
||||
[ "${usg}" == "Y" ] && usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
make_inventory() {
|
||||
local scenario=$1 engine=${2:-podman}
|
||||
inventory="${test_env}/inventory"
|
||||
log info "Inventory file: ${inventory}"
|
||||
cat << EOF > "${inventory}"
|
||||
[ipaserver]
|
||||
${scenario} ansible_connection=${engine}
|
||||
[ipaserver:vars]
|
||||
ipaserver_domain = test.local
|
||||
ipaserver_realm = TEST.LOCAL
|
||||
EOF
|
||||
}
|
||||
|
||||
stop_container() {
|
||||
local scenario=${1} engine=${2:-podman}
|
||||
echo "Stopping container..."
|
||||
quiet "${engine}" stop "${scenario}"
|
||||
echo "Removing container..."
|
||||
quiet "${engine}" rm "${scenario}"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [ $# -gt 0 ]
|
||||
then
|
||||
if [ "${STOP_CONTAINER}" != "N" ]
|
||||
then
|
||||
stop_container "${1}" "${2}"
|
||||
rm "${inventory}"
|
||||
else
|
||||
log info "Keeping container: $(podman ps --format "{{.Names}} - {{.ID}}" --filter "name=${1}")"
|
||||
fi
|
||||
fi
|
||||
if [ "${STOP_VIRTUALENV}" == "Y" ]
|
||||
then
|
||||
echo "Deactivating virtual environment"
|
||||
deactivate
|
||||
fi
|
||||
}
|
||||
|
||||
list_images() {
|
||||
local quay_api="https://quay.io/api/v1/repository/ansible-freeipa/upstream-tests/tag"
|
||||
echo -e "${WHITE}Available images:"
|
||||
curl --silent -L "${quay_api}" | jq '.tags[]|.name' | tr -d '"'| sort | uniq | sed "s/.*/ &/"
|
||||
echo -e "${RST}"
|
||||
}
|
||||
|
||||
# Defaults
|
||||
|
||||
ANSIBLE_VERSION=${ANSIBLE_VERSION:-'ansible-core'}
|
||||
verbose=""
|
||||
FORCE_ENV="N"
|
||||
engine="${engine:-"podman"}"
|
||||
CONTINUE_ON_ERROR=""
|
||||
STOP_CONTAINER="Y"
|
||||
STOP_VIRTUALENV="N"
|
||||
declare -a ENABLED_MODULES
|
||||
declare -a ENABLED_TESTS
|
||||
ENABLED_MODULES=()
|
||||
ENABLED_TESTS=()
|
||||
test_env="${TESTENV_DIR:-${VIRTUAL_ENV:-/tmp/ansible-freeipa-tests}}"
|
||||
engine="podman"
|
||||
IMAGE_REPO="quay.io/ansible-freeipa/upstream-tests"
|
||||
read -r -a ENABLED_MODULES <<< "${IPA_ENABLED_MODULES:-""}"
|
||||
read -r -a ENABLED_TESTS <<< "${IPA_ENABLED_MODULES:-""}"
|
||||
IMAGE_TAG="fedora-latest"
|
||||
scenario=""
|
||||
scenario="freeipa-tests"
|
||||
MEMORY=3
|
||||
hostname="ipaserver.test.local"
|
||||
SEED=""
|
||||
GROUP=0
|
||||
IPA_HOSTNAME="ipaserver.test.local"
|
||||
SEED="$(date "+%Y%m%d")"
|
||||
GROUP=1
|
||||
SPLITS=0
|
||||
ANSIBLE_COLLECTIONS=${ANSIBLE_COLLECTIONS:-"containers.podman"}
|
||||
|
||||
ANSIBLE_COLLECTIONS=${ANSIBLE_COLLECTIONS:-"${engine_collection}"}
|
||||
SKIP_ANSIBLE=""
|
||||
ansible_interpreter="/usr/bin/python3"
|
||||
EXTRA_OPTIONS=""
|
||||
unset ANSIBLE_VERSION
|
||||
|
||||
# Process command options
|
||||
|
||||
while getopts ":hA:c:ei:Klms:vx" option
|
||||
while getopts ":ha:Ac:ei:Klm:p:s:S:vx" option
|
||||
do
|
||||
case "$option" in
|
||||
h) help && exit 0 ;;
|
||||
A)
|
||||
[ ${#ENABLED_MODULES[@]} -eq 0 ] || die -u "Can't use '-A' with '-s'"
|
||||
SEED="$(cut -d. -f1 <<< "${OPTARG}" | tr -d "-")"
|
||||
GROUP="$(cut -d. -f2 <<< "${OPTARG}")"
|
||||
if [ -z "${SEED}" ] || [ -z "${GROUP}" ]
|
||||
then
|
||||
die -u "Seed for '-A' must have the format YYYYMMDD.N"
|
||||
fi
|
||||
SPLITS=3
|
||||
;;
|
||||
[ -n "${ANSIBLE_VERSION:-""}" ] && die "Can't use -A with '-a'"
|
||||
SKIP_ANSIBLE="YES"
|
||||
;;
|
||||
a)
|
||||
[ "${SKIP_ANSIBLE:-"no"}" == "YES" ] && die "Can't use -A with '-a'"
|
||||
ANSIBLE_VERSION="${OPTARG}"
|
||||
;;
|
||||
c) scenario="${OPTARG}" ;;
|
||||
e) FORCE_ENV="Y" ;;
|
||||
i) IMAGE_TAG="${OPTARG}" ;;
|
||||
K) STOP_CONTAINER="N" ;;
|
||||
l) list_images && exit 0 || exit 1;;
|
||||
l) "${SCRIPTDIR}"/setup_test_container.sh -l && exit 0 || exit 1 ;;
|
||||
m) MEMORY="${OPTARG}" ;;
|
||||
p) ansible_interpreter="${OPTARG}" ;;
|
||||
s)
|
||||
[ ${SPLITS} -ne 0 ] && die -u "Can't use '-A' with '-s'"
|
||||
[ ${SPLITS} -ne 0 ] && die -u "Can't use '-S' with '-s'"
|
||||
if [ -d "${TOPDIR}/tests/${OPTARG}" ]
|
||||
then
|
||||
ENABLED_MODULES+=("${OPTARG}")
|
||||
@@ -220,6 +101,16 @@ do
|
||||
log error "Invalid suite: ${OPTARG}"
|
||||
fi
|
||||
;;
|
||||
S)
|
||||
[ ${#ENABLED_MODULES[@]} -eq 0 ] || die -u "Can't use '-A' with '-s'"
|
||||
SEED="$(cut -d. -f1 <<< "${OPTARG}" | tr -d "-")"
|
||||
GROUP="$(cut -d. -f2 <<< "${OPTARG}")"
|
||||
if [ -z "${SEED}" ] || [ -z "${GROUP}" ]
|
||||
then
|
||||
die -u "Seed for '-A' must have the format YYYYMMDD.N"
|
||||
fi
|
||||
SPLITS=3
|
||||
;;
|
||||
v) verbose=${verbose:--}${option} ;;
|
||||
x) EXTRA_OPTIONS="$EXTRA_OPTIONS --exitfirst" ;;
|
||||
*) die -u "Invalid option: ${OPTARG}" ;;
|
||||
@@ -240,155 +131,28 @@ done
|
||||
|
||||
[ ${SPLITS} -eq 0 ] && [ ${#ENABLED_MODULES[@]} -eq 0 ] && [ ${#ENABLED_TESTS[@]} -eq 0 ] && die -u "No test defined."
|
||||
|
||||
export STOP_CONTAINER FORCE_ENV STOP_VIRTUALENV ansible_interpreter
|
||||
|
||||
# Ensure $python is set
|
||||
[ -z "${python}" ] && python="python3"
|
||||
|
||||
log info "Controller Python executable: ${python}"
|
||||
${python} --version
|
||||
|
||||
# Prepare virtual environment
|
||||
VENV=$(in_python_virtualenv && echo Y || echo N)
|
||||
start_virtual_environment
|
||||
log info "Installing dependencies from 'requirements-tests.txt'"
|
||||
pip install --upgrade -r "${TOPDIR}/requirements-tests.txt"
|
||||
|
||||
if [ "${FORCE_ENV}" == "Y" ]
|
||||
then
|
||||
[ "${VENV}" == "Y" ] && deactivate
|
||||
VENV="N"
|
||||
rm -rf "$test_env"
|
||||
log info "Virtual environment will be (re)created."
|
||||
fi
|
||||
|
||||
if [ "$VENV" == "N" ]
|
||||
then
|
||||
log info "Preparing virtual environment: ${test_env}"
|
||||
if [ ! -d "${test_env}" ]
|
||||
then
|
||||
log info "Creating virtual environment: ${test_env}..."
|
||||
if ! python3 -m venv "${test_env}"
|
||||
then
|
||||
die "Cannot create virtual environment."
|
||||
fi
|
||||
fi
|
||||
if [ -f "${test_env}/bin/activate" ]
|
||||
then
|
||||
log info "Starting virtual environment: ${test_env}"
|
||||
# shellcheck disable=SC1091
|
||||
. "${test_env}/bin/activate" || die "Cannot activate environment."
|
||||
STOP_VIRTUALENV="Y"
|
||||
else
|
||||
die "Cannot activate environment."
|
||||
fi
|
||||
log info "Installing required tools."
|
||||
log none "Upgrading: pip setuptools wheel"
|
||||
pip install --quiet --upgrade pip setuptools wheel
|
||||
log info "Installing dependencies from 'requirements-tests.txt'"
|
||||
pip install --quiet -r "${TOPDIR}/requirements-tests.txt"
|
||||
log info "Installing Ansible: ${ANSIBLE_VERSION}"
|
||||
pip install --quiet "${ANSIBLE_VERSION}"
|
||||
log debug "Ansible version: $(ansible --version | sed -n "1p")${RST}"
|
||||
else
|
||||
log info "Using current virtual environment."
|
||||
fi
|
||||
|
||||
if [ -n "${ANSIBLE_COLLECTIONS}" ]
|
||||
then
|
||||
log warn "Installed collections will not be removed after execution."
|
||||
log none "Installing: Ansible Collection ${ANSIBLE_COLLECTIONS}"
|
||||
# shellcheck disable=SC2086
|
||||
quiet ansible-galaxy collection install ${ANSIBLE_COLLECTIONS} || die "Failed to install Ansible collections."
|
||||
fi
|
||||
[ -z "${SKIP_ANSIBLE}" ] && install_ansible "${ANSIBLE_VERSION:-"ansible-core"}"
|
||||
|
||||
# Ansible configuration
|
||||
export ANSIBLE_ROLES_PATH="${TOPDIR}/roles"
|
||||
export ANSIBLE_LIBRARY="${TOPDIR}/plugins:${TOPDIR}/molecule"
|
||||
export ANSIBLE_LIBRARY="${TOPDIR}/plugins"
|
||||
export ANSIBLE_MODULE_UTILS="${TOPDIR}/plugins/module_utils"
|
||||
|
||||
# Prepare container
|
||||
container_id=""
|
||||
container_status=("-f" "status=created" "-f" "status=running")
|
||||
[ -n "${scenario}" ] && container_id="$(${engine} ps --all -q -f "name=${scenario}" "${container_status[@]}")"
|
||||
if [ -z "${container_id}" ]
|
||||
then
|
||||
# Retrieve image and start container.
|
||||
log info "Pulling FreeIPA image '${IMAGE_REPO}:${IMAGE_TAG}'..."
|
||||
img_id=$(${engine} pull -q "${IMAGE_REPO}:${IMAGE_TAG}")
|
||||
log info "Creating container..."
|
||||
CONFIG="--hostname ${hostname} --memory ${MEMORY}g --memory-swap -1 --dns none --add-host ipaserver.test.local:127.0.0.1"
|
||||
[ -n "${scenario}" ] && CONFIG="${CONFIG} --name ${scenario}"
|
||||
# shellcheck disable=SC2086
|
||||
container_id=$(${engine} create ${CONFIG} "${img_id}" || die "Cannot create container")
|
||||
echo "CONTAINER: ${container_id}"
|
||||
fi
|
||||
scenario="${scenario:-$(${engine} ps -q --format "{{.Names}}" --filter "id=${container_id}" "${container_status[@]}")}"
|
||||
log debug "Using container: ${scenario}"
|
||||
|
||||
# Start container
|
||||
make_inventory "${scenario}"
|
||||
log info "Starting container for ${scenario}..."
|
||||
quiet ${engine} start "${scenario}"
|
||||
|
||||
# create /etc/resolve.conf
|
||||
run_inline_playbook <<EOF || die "Failed to create /etc/resolv.conf"
|
||||
---
|
||||
- name: Create /etc/resolv.conf
|
||||
hosts: ipaserver
|
||||
gather_facts: no
|
||||
become: yes
|
||||
tasks:
|
||||
- name: Create /etc/resolv.conf
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/resolv.conf
|
||||
mode: 0644
|
||||
content: |
|
||||
search test.local
|
||||
nameserver 127.0.0.1
|
||||
...
|
||||
EOF
|
||||
|
||||
# wait for FreeIPA services to be available
|
||||
run_inline_playbook <<EOF || die "Failed to verify IPA or KDC services."
|
||||
---
|
||||
- name: Wait for IPA services to be available
|
||||
hosts: ipaserver
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Wait for IPA to be started.
|
||||
ansible.builtin.systemd:
|
||||
name: ipa
|
||||
state: started
|
||||
- name: Wait for Kerberos KDC to be started.
|
||||
ansible.builtin.systemd:
|
||||
name: krb5kdc
|
||||
state: started
|
||||
register: result
|
||||
until: not result.failed
|
||||
retries: 30
|
||||
delay: 5
|
||||
- name: Check if TGT is available for admin.
|
||||
ansible.builtin.shell:
|
||||
cmd: echo SomeADMINpassword | kinit -c ansible_freeipa_cache admin
|
||||
register: result
|
||||
until: not result.failed
|
||||
retries: 30
|
||||
delay: 5
|
||||
- name: Cleanup TGT.
|
||||
ansible.builtin.shell:
|
||||
cmd: kdestroy -c ansible_freeipa_cache -A
|
||||
...
|
||||
EOF
|
||||
|
||||
# check image software versions.
|
||||
run_inline_playbook <<EOF || die "Failed to verify software installation."
|
||||
---
|
||||
- name: Software environment.
|
||||
hosts: ipaserver
|
||||
become: yes
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Retrieve versions.
|
||||
shell:
|
||||
cmd: |
|
||||
rpm -q freeipa-server freeipa-client ipa-server ipa-client 389-ds-base pki-ca krb5-server
|
||||
cat /etc/redhat-release
|
||||
uname -a
|
||||
register: result
|
||||
- name: Testing environment.
|
||||
debug:
|
||||
var: result.stdout_lines
|
||||
EOF
|
||||
"${SCRIPTDIR}/setup_test_container.sh" -e "${engine}" -m "${MEMORY}" -p "${ansible_interpreter}" -i "${IMAGE_TAG}" -n "${IPA_HOSTNAME}" -a "${scenario}" || die "Failed to setup test container"
|
||||
|
||||
|
||||
# run tests
|
||||
@@ -396,6 +160,9 @@ RESULT=0
|
||||
|
||||
export RUN_TESTS_IN_DOCKER=${engine}
|
||||
export IPA_SERVER_HOST="${scenario}"
|
||||
# Ensure proper ansible_python_interpreter is used by pytest.
|
||||
export IPA_PYTHON_PATH="${ansible_interpreter}"
|
||||
|
||||
if [ ${SPLITS} -ne 0 ]
|
||||
then
|
||||
EXTRA_OPTIONS="${EXTRA_OPTIONS} --splits=${SPLITS} --group=${GROUP} --randomly-seed=${SEED}"
|
||||
@@ -417,11 +184,11 @@ IPA_VERBOSITY="${verbose}"
|
||||
[ -n "${IPA_VERBOSITY}" ] && export IPA_VERBOSITY
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
if ! pytest -m "playbook" --verbose --color=yes ${EXTRA_OPTIONS}
|
||||
if ! pytest -m "playbook" --verbose --color=yes --suppress-no-test-exit-code --junit-xml=TEST-results-group-${GROUP:-1}.xml ${EXTRA_OPTIONS}
|
||||
then
|
||||
RESULT=2
|
||||
log error "Container not stopped for verification: ${scenario}"
|
||||
log info "Container: $(podman ps -f "id=${container_id}" --format "{{.Names}} - {{.ID}}")"
|
||||
log info "Container: $(${engine} ps -f "name=${scenario}" --format "{{.Names}} - {{.ID}}")"
|
||||
fi
|
||||
[ -z "${CONTINUE_ON_ERROR}" ] && [ $RESULT -ne 0 ] && die "Stopping on test failure."
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ die() {
|
||||
|
||||
TOPDIR="$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
[ -n "$(command -v python3)" ] && python="$(command -v python3)" || python="$(command -v python2)"
|
||||
|
||||
pushd "${TOPDIR}" >/dev/null 2>&1 || die "Failed to change directory."
|
||||
|
||||
files_list=$(mktemp)
|
||||
@@ -25,7 +27,7 @@ git diff "${remote}/master" --name-only > "${files_list}"
|
||||
git remote remove ${remote}
|
||||
|
||||
# Get all modules that should have tests executed
|
||||
enabled_modules="$(python utils/get_test_modules.py $(cat "${files_list}"))"
|
||||
enabled_modules="$(${python} utils/get_test_modules.py $(cat "${files_list}"))"
|
||||
[ -z "${enabled_modules}" ] && enabled_modules="None"
|
||||
|
||||
# Get individual tests that should be executed
|
||||
|
||||
119
utils/setup_test_container.sh
Executable file
119
utils/setup_test_container.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
SCRIPTDIR="$(readlink -f "$(dirname "$0")")"
|
||||
|
||||
# shellcheck source=utils/shcontainer
|
||||
. "${SCRIPTDIR}/shcontainer"
|
||||
# shellcheck source=utils/shansible
|
||||
. "${SCRIPTDIR}/shansible"
|
||||
|
||||
usage() {
|
||||
local prog="${0##*/}"
|
||||
cat <<EOF
|
||||
usage: ${prog} [-h] [-l] [-a] [-e ENGINE] [-i IMAGE] [-m MEMORY] [-n HOSTNAME] NAME
|
||||
${prog} starts a container to test ansible-freeipa.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
help() {
|
||||
usage
|
||||
echo -e "$(cat <<EOF
|
||||
Arguments:
|
||||
|
||||
NAME set the container name
|
||||
|
||||
Options:
|
||||
|
||||
-h display this message and exit
|
||||
-l list available images
|
||||
-a Test Ansible connection.
|
||||
-e ENGINE set the container engine to use
|
||||
(default: ${WHITE}podman${RST}, if available)
|
||||
-i IMAGE select image to run the tests (default: fedora-latest)
|
||||
-m MEMORY set container memory, in GiB (default: 3)
|
||||
-n HOSTNAME set the hostname in the container
|
||||
(default: ipaserver.test.local)
|
||||
-p INTERPRETER Python interpreter to use on target container
|
||||
EOF
|
||||
)"
|
||||
}
|
||||
|
||||
list_images() {
|
||||
local quay_api="https://quay.io/api/v1/repository/ansible-freeipa/upstream-tests/tag"
|
||||
echo -e "${WHITE}Available images:"
|
||||
curl --silent -L "${quay_api}" | jq '.tags[]|.name' | tr -d '"'| sort | uniq | sed "s/.*/ &/"
|
||||
echo -e "${RST}"
|
||||
}
|
||||
|
||||
IMAGE_TAG="fedora-latest"
|
||||
MEMORY="${MEMORY:-3}"
|
||||
IPA_HOSTNAME="${IPA_HOSTNAME:-"ipaserver.test.local"}"
|
||||
test_env="${test_env:-"/tmp"}"
|
||||
ansible_interpreter="/usr/bin/python3"
|
||||
engine="podman"
|
||||
ansible_test=""
|
||||
|
||||
while getopts ":hae:i:lm:n:p:" option
|
||||
do
|
||||
case "$option" in
|
||||
h) help && exit 0 ;;
|
||||
a) ansible_test="yes" ;;
|
||||
e) engine="${OPTARG}" ;;
|
||||
i) IMAGE_TAG="${OPTARG}" ;;
|
||||
l) list_images && exit 0 || exit 1;;
|
||||
m) MEMORY="${OPTARG}" ;;
|
||||
n) IPA_HOSTNAME="${OPTARG}" ;;
|
||||
p) ansible_interpreter="${OPTARG}" ;;
|
||||
*) die -u "Invalid option: ${OPTARG}" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
export IPA_HOSTNAME MEMORY IMAGE_TAG scenario
|
||||
|
||||
shift $((OPTIND - 1))
|
||||
[ $# == 1 ] || die -u "You must provide the name for a single container."
|
||||
scenario="${1}"
|
||||
shift
|
||||
|
||||
prepare_container "${scenario}" "${IMAGE_TAG}"
|
||||
start_container "${scenario}"
|
||||
|
||||
# wait for FreeIPA services to be available (usually ~45 seconds)
|
||||
log info "Wait for container to be initialized."
|
||||
wait=15
|
||||
while podman exec "${scenario}" systemctl list-jobs | grep -qvi "no jobs running"
|
||||
do
|
||||
log none "Waiting ${wait}s... "
|
||||
sleep "${wait}"
|
||||
log none "Retrying".
|
||||
done
|
||||
|
||||
# run tests
|
||||
|
||||
# ensure we can get a TGT for admin
|
||||
log info "Testing kinit with admin."
|
||||
# shellcheck disable=SC2016
|
||||
"${engine}" exec "${scenario}" /bin/sh -c 'for i in $(seq 5); do echo "SomeADMINpassword" | kinit -c ansible_freeipa_cache admin && kdestroy -c ansible_freeipa_cache -A && break; echo "Failed to get TGT. Retrying in 10s..."; sleep 10; done' || die "Failed to grant admin TGT."
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
log info "Creating inventory."
|
||||
make_inventory "${scenario}" "${engine}" "${ansible_interpreter:-"/usr/bin/python3"}"
|
||||
if [ -z "${inventory:-''}" ]
|
||||
then
|
||||
log error "Could not create inventory file."
|
||||
else
|
||||
# shellcheck disable=SC2154
|
||||
log info "Inventory path: [${inventory}]"
|
||||
# shellcheck disable=SC2154
|
||||
log debug "$(cat "${inventory}")"
|
||||
if [ "${ansible_test}" == "yes" ]
|
||||
then
|
||||
log info "Testing Ansible connection."
|
||||
# shellcheck disable=SC2154
|
||||
run_if_exists ansible_ping "${inventory}"
|
||||
log info "Querying installed software"
|
||||
run_if_exists query_container_installed_software
|
||||
fi
|
||||
fi
|
||||
|
||||
88
utils/shansible
Normal file
88
utils/shansible
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash -eu
|
||||
# This file is meant to be source'd by other scripts
|
||||
|
||||
SCRIPTDIR="$(dirname -- "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||
|
||||
# shellcheck source=utils/shfun
|
||||
. "${SCRIPTDIR}/shfun"
|
||||
|
||||
install_ansible() {
|
||||
ANSIBLE_VERSION="${1:-${ANSIBLE_VERSION:-"ansible-core"}}"
|
||||
[ $# -gt 0 ] && shift
|
||||
log info "Installing Ansible: ${ANSIBLE_VERSION}"
|
||||
pip install --quiet "${ANSIBLE_VERSION}"
|
||||
log debug "Ansible version: $(ansible --version | sed -n "1p")${RST}"
|
||||
|
||||
if [ -n "${ANSIBLE_COLLECTIONS}" ]
|
||||
then
|
||||
log warn "Installed collections will not be removed after execution."
|
||||
log none "Installing: Ansible Collection ${ANSIBLE_COLLECTIONS}"
|
||||
# shellcheck disable=SC2086
|
||||
quiet ansible-galaxy collection install ${ANSIBLE_COLLECTIONS} || die "Failed to install Ansible collections."
|
||||
fi
|
||||
export ANSIBLE_VERSION
|
||||
}
|
||||
|
||||
run_inline_playbook() {
|
||||
local playbookdir playbook err
|
||||
playbookdir=${1:-"playbooks"}
|
||||
quiet mkdir -p "${playbookdir}"
|
||||
playbook=$(mktemp "${playbookdir}/ansible-freeipa-test-playbook_ipa.XXXXXXXX" 2>/dev/null)
|
||||
# In some configurations, it may not be possible to use another
|
||||
# directory, so we store the playbook in the current one.
|
||||
# [ -z "${playbook}" ] && playbook=$(mktemp "ansible-freeipa-test-playbook_ipa.XXXXXXXX")
|
||||
|
||||
inventory="${inventory:-${test_env:-"."}/inventory}"
|
||||
quiet mkdir -p "${playbookdir}"
|
||||
cat - >"${playbook}"
|
||||
# shellcheck disable=SC2086
|
||||
run_if_exists ansible-playbook ${ansible_options:-} -i "${inventory}" "${playbook}"
|
||||
err=$?
|
||||
rm -f "${playbook}"
|
||||
return ${err}
|
||||
}
|
||||
|
||||
make_inventory() {
|
||||
local scenario pod_engine ansible_interpreter
|
||||
scenario=$1
|
||||
pod_engine="${engine:-${2:-podman}}"
|
||||
ansible_interpreter="${3:-${ansible_interpreter:-"/usr/bin/python3"}}"
|
||||
export inventory="${test_env:-"."}/inventory"
|
||||
log info "Inventory file: ${inventory}"
|
||||
cat << EOF > "${inventory}"
|
||||
[ipaserver]
|
||||
${scenario} ansible_connection=${pod_engine} ansible_python_interpreter=${ansible_interpreter}
|
||||
[ipaserver:vars]
|
||||
ipaserver_domain = test.local
|
||||
ipaserver_realm = TEST.LOCAL
|
||||
EOF
|
||||
}
|
||||
|
||||
query_container_installed_software() {
|
||||
# check image software versions.
|
||||
run_inline_playbook "${test_env:-"/tmp"}/playbooks" <<EOF || die "Failed to verify software installation."
|
||||
---
|
||||
- name: Software environment.
|
||||
hosts: ipaserver
|
||||
become: yes
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Retrieve versions.
|
||||
ansible.builtin.shell: |
|
||||
cat /etc/redhat-release
|
||||
${python:-"python3"} --version
|
||||
rpm -q freeipa-server freeipa-client ipa-server ipa-client 389-ds-base pki-ca krb5-server
|
||||
uname -a
|
||||
register: result
|
||||
- name: Testing environment.
|
||||
ansible.builtin.debug:
|
||||
var: result.stdout_lines
|
||||
EOF
|
||||
}
|
||||
|
||||
ansible_ping() {
|
||||
# shellcheck disable=SC2086
|
||||
ansible ${ansible_options:-} -m ping -i "${1:-${inventory}}" all || die "Could not connect to container."
|
||||
}
|
||||
|
||||
export ANSIBLE_VERSION=${ANSIBLE_VERSION:-'ansible-core'}
|
||||
61
utils/shcontainer
Normal file
61
utils/shcontainer
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash -eu
|
||||
# This file is meant to be source'd by other scripts
|
||||
|
||||
SCRIPTDIR="$(dirname -- "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||
|
||||
IMAGE_REPO="quay.io/ansible-freeipa/upstream-tests"
|
||||
|
||||
# shellcheck source=utils/shfun
|
||||
. "${SCRIPTDIR}/shfun"
|
||||
|
||||
stop_container() {
|
||||
local scenario=${1}
|
||||
log none "Stopping container..."
|
||||
quiet "${engine}" stop "${scenario}"
|
||||
log none "Removing container..."
|
||||
quiet "${engine}" rm "${scenario}"
|
||||
}
|
||||
|
||||
# Prepare container
|
||||
prepare_container() {
|
||||
local container_id container_status hostname scenario
|
||||
local IMAGE_TAG img_id CONFIG
|
||||
container_id=""
|
||||
container_status=("-f" "status=created" "-f" "status=running")
|
||||
hostname="${IPA_HOSTNAME:-"ipaserver.test.local"}"
|
||||
scenario="${1:-${scenario:-"freeipa-tests"}}"
|
||||
IMAGE_TAG="${2:-${IMAGE_TAG:-fedora-latest}}"
|
||||
[ -n "${scenario}" ] && container_id="$(${engine} ps --all -q -f "name=${scenario}" "${container_status[@]}")"
|
||||
if [ -z "${container_id}" ]
|
||||
then
|
||||
# Retrieve image and start container.
|
||||
log info "Pulling FreeIPA image '${IMAGE_REPO}:${IMAGE_TAG}'..."
|
||||
img_id=$(${engine} pull -q "${IMAGE_REPO}:${IMAGE_TAG}")
|
||||
log debug "Hostname: ${hostname}"
|
||||
log info "Creating container..."
|
||||
CONFIG="--systemd true --hostname ${hostname} --memory ${MEMORY}g --memory-swap -1 --no-hosts"
|
||||
[ -n "${scenario}" ] && CONFIG="${CONFIG} --name ${scenario}"
|
||||
# shellcheck disable=SC2086
|
||||
container_id=$(${engine} create ${CONFIG} "${img_id}" || die "Cannot create container")
|
||||
log none "CONTAINER: ${container_id}"
|
||||
fi
|
||||
export scenario="${scenario:-$(${engine} ps -q --format "{{.Names}}" --filter "id=${container_id}" "${container_status[@]}")}"
|
||||
log debug "Prepared container: ${scenario}"
|
||||
}
|
||||
|
||||
start_container() {
|
||||
local scenario="${1:-${scenario}}"
|
||||
log info "Starting container for ${scenario}..."
|
||||
"${engine}" start "${scenario}"
|
||||
}
|
||||
|
||||
if [ -z "$(command -v podman)" ]
|
||||
then
|
||||
engine="docker"
|
||||
engine_collection="community.docker"
|
||||
else
|
||||
engine="podman"
|
||||
engine_collection="containers.podman"
|
||||
fi
|
||||
|
||||
export engine engine_collection
|
||||
Reference in New Issue
Block a user