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
|
#!/bin/bash -eu
|
||||||
|
|
||||||
trap interrupt_exception SIGINT
|
SCRIPTDIR="$(readlink -f "$(dirname "$0")")"
|
||||||
|
TOPDIR="$(readlink -f "${SCRIPTDIR}/..")"
|
||||||
|
|
||||||
RST="\033[0m"
|
# shellcheck source=utils/shfun
|
||||||
RED="\033[31m"
|
. "${SCRIPTDIR}/shfun"
|
||||||
# BRIGHTRED="\033[31;1m"
|
# shellcheck source=utils/shcontainer
|
||||||
# GREEN="\033[32m"
|
. "${SCRIPTDIR}/shcontainer"
|
||||||
BRIGHTGREEN="\033[32;1m"
|
# shellcheck source=utils/shansible
|
||||||
# BROWN="\033[33m"
|
. "${SCRIPTDIR}/shansible"
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
local prog="${0##*/}"
|
local prog="${0##*/}"
|
||||||
cat <<EOF
|
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.
|
${prog} runs playbook(s) TEST using an ansible-freeipa testing image.
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
@@ -47,172 +28,72 @@ positional arguments:
|
|||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h display this message and exit
|
-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
|
-c CONTAINER use container CONTAINER to run tests
|
||||||
-K keep container, even if tests succeed
|
-K keep container, even if tests succeed
|
||||||
-l list available images
|
-l list available images
|
||||||
-e force recreation of the virtual environment
|
-e force recreation of the virtual environment
|
||||||
-i IMAGE select image to run the tests (default: fedora-latest)
|
-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
|
-s TEST_SUITE run all playbooks for test suite, which is a directory
|
||||||
under ${WHITE}tests${RST}
|
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)
|
-v Increase Ansible verbosity (can be used multiple times)
|
||||||
-x Stop on first error.
|
-x Stop on first error.
|
||||||
EOF
|
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
|
# Defaults
|
||||||
|
|
||||||
ANSIBLE_VERSION=${ANSIBLE_VERSION:-'ansible-core'}
|
|
||||||
verbose=""
|
verbose=""
|
||||||
FORCE_ENV="N"
|
engine="${engine:-"podman"}"
|
||||||
CONTINUE_ON_ERROR=""
|
CONTINUE_ON_ERROR=""
|
||||||
STOP_CONTAINER="Y"
|
STOP_CONTAINER="Y"
|
||||||
STOP_VIRTUALENV="N"
|
STOP_VIRTUALENV="N"
|
||||||
declare -a ENABLED_MODULES
|
declare -a ENABLED_MODULES
|
||||||
declare -a ENABLED_TESTS
|
declare -a ENABLED_TESTS
|
||||||
ENABLED_MODULES=()
|
read -r -a ENABLED_MODULES <<< "${IPA_ENABLED_MODULES:-""}"
|
||||||
ENABLED_TESTS=()
|
read -r -a ENABLED_TESTS <<< "${IPA_ENABLED_MODULES:-""}"
|
||||||
test_env="${TESTENV_DIR:-${VIRTUAL_ENV:-/tmp/ansible-freeipa-tests}}"
|
|
||||||
engine="podman"
|
|
||||||
IMAGE_REPO="quay.io/ansible-freeipa/upstream-tests"
|
|
||||||
IMAGE_TAG="fedora-latest"
|
IMAGE_TAG="fedora-latest"
|
||||||
scenario=""
|
scenario="freeipa-tests"
|
||||||
MEMORY=3
|
MEMORY=3
|
||||||
hostname="ipaserver.test.local"
|
IPA_HOSTNAME="ipaserver.test.local"
|
||||||
SEED=""
|
SEED="$(date "+%Y%m%d")"
|
||||||
GROUP=0
|
GROUP=1
|
||||||
SPLITS=0
|
SPLITS=0
|
||||||
ANSIBLE_COLLECTIONS=${ANSIBLE_COLLECTIONS:-"containers.podman"}
|
ANSIBLE_COLLECTIONS=${ANSIBLE_COLLECTIONS:-"${engine_collection}"}
|
||||||
|
SKIP_ANSIBLE=""
|
||||||
|
ansible_interpreter="/usr/bin/python3"
|
||||||
EXTRA_OPTIONS=""
|
EXTRA_OPTIONS=""
|
||||||
|
unset ANSIBLE_VERSION
|
||||||
|
|
||||||
# Process command options
|
# Process command options
|
||||||
|
|
||||||
while getopts ":hA:c:ei:Klms:vx" option
|
while getopts ":ha:Ac:ei:Klm:p:s:S:vx" option
|
||||||
do
|
do
|
||||||
case "$option" in
|
case "$option" in
|
||||||
h) help && exit 0 ;;
|
h) help && exit 0 ;;
|
||||||
A)
|
A)
|
||||||
[ ${#ENABLED_MODULES[@]} -eq 0 ] || die -u "Can't use '-A' with '-s'"
|
[ -n "${ANSIBLE_VERSION:-""}" ] && die "Can't use -A with '-a'"
|
||||||
SEED="$(cut -d. -f1 <<< "${OPTARG}" | tr -d "-")"
|
SKIP_ANSIBLE="YES"
|
||||||
GROUP="$(cut -d. -f2 <<< "${OPTARG}")"
|
;;
|
||||||
if [ -z "${SEED}" ] || [ -z "${GROUP}" ]
|
a)
|
||||||
then
|
[ "${SKIP_ANSIBLE:-"no"}" == "YES" ] && die "Can't use -A with '-a'"
|
||||||
die -u "Seed for '-A' must have the format YYYYMMDD.N"
|
ANSIBLE_VERSION="${OPTARG}"
|
||||||
fi
|
;;
|
||||||
SPLITS=3
|
|
||||||
;;
|
|
||||||
c) scenario="${OPTARG}" ;;
|
c) scenario="${OPTARG}" ;;
|
||||||
e) FORCE_ENV="Y" ;;
|
e) FORCE_ENV="Y" ;;
|
||||||
i) IMAGE_TAG="${OPTARG}" ;;
|
i) IMAGE_TAG="${OPTARG}" ;;
|
||||||
K) STOP_CONTAINER="N" ;;
|
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}" ;;
|
m) MEMORY="${OPTARG}" ;;
|
||||||
|
p) ansible_interpreter="${OPTARG}" ;;
|
||||||
s)
|
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}" ]
|
if [ -d "${TOPDIR}/tests/${OPTARG}" ]
|
||||||
then
|
then
|
||||||
ENABLED_MODULES+=("${OPTARG}")
|
ENABLED_MODULES+=("${OPTARG}")
|
||||||
@@ -220,6 +101,16 @@ do
|
|||||||
log error "Invalid suite: ${OPTARG}"
|
log error "Invalid suite: ${OPTARG}"
|
||||||
fi
|
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} ;;
|
v) verbose=${verbose:--}${option} ;;
|
||||||
x) EXTRA_OPTIONS="$EXTRA_OPTIONS --exitfirst" ;;
|
x) EXTRA_OPTIONS="$EXTRA_OPTIONS --exitfirst" ;;
|
||||||
*) die -u "Invalid option: ${OPTARG}" ;;
|
*) 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."
|
[ ${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
|
# 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" ]
|
[ -z "${SKIP_ANSIBLE}" ] && install_ansible "${ANSIBLE_VERSION:-"ansible-core"}"
|
||||||
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
|
|
||||||
|
|
||||||
# Ansible configuration
|
# Ansible configuration
|
||||||
export ANSIBLE_ROLES_PATH="${TOPDIR}/roles"
|
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"
|
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
|
# Start container
|
||||||
make_inventory "${scenario}"
|
"${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"
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
# run tests
|
# run tests
|
||||||
@@ -396,6 +160,9 @@ RESULT=0
|
|||||||
|
|
||||||
export RUN_TESTS_IN_DOCKER=${engine}
|
export RUN_TESTS_IN_DOCKER=${engine}
|
||||||
export IPA_SERVER_HOST="${scenario}"
|
export IPA_SERVER_HOST="${scenario}"
|
||||||
|
# Ensure proper ansible_python_interpreter is used by pytest.
|
||||||
|
export IPA_PYTHON_PATH="${ansible_interpreter}"
|
||||||
|
|
||||||
if [ ${SPLITS} -ne 0 ]
|
if [ ${SPLITS} -ne 0 ]
|
||||||
then
|
then
|
||||||
EXTRA_OPTIONS="${EXTRA_OPTIONS} --splits=${SPLITS} --group=${GROUP} --randomly-seed=${SEED}"
|
EXTRA_OPTIONS="${EXTRA_OPTIONS} --splits=${SPLITS} --group=${GROUP} --randomly-seed=${SEED}"
|
||||||
@@ -417,11 +184,11 @@ IPA_VERBOSITY="${verbose}"
|
|||||||
[ -n "${IPA_VERBOSITY}" ] && export IPA_VERBOSITY
|
[ -n "${IPA_VERBOSITY}" ] && export IPA_VERBOSITY
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# 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
|
then
|
||||||
RESULT=2
|
RESULT=2
|
||||||
log error "Container not stopped for verification: ${scenario}"
|
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
|
fi
|
||||||
[ -z "${CONTINUE_ON_ERROR}" ] && [ $RESULT -ne 0 ] && die "Stopping on test failure."
|
[ -z "${CONTINUE_ON_ERROR}" ] && [ $RESULT -ne 0 ] && die "Stopping on test failure."
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ die() {
|
|||||||
|
|
||||||
TOPDIR="$(dirname "${BASH_SOURCE[0]}")/.."
|
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."
|
pushd "${TOPDIR}" >/dev/null 2>&1 || die "Failed to change directory."
|
||||||
|
|
||||||
files_list=$(mktemp)
|
files_list=$(mktemp)
|
||||||
@@ -25,7 +27,7 @@ git diff "${remote}/master" --name-only > "${files_list}"
|
|||||||
git remote remove ${remote}
|
git remote remove ${remote}
|
||||||
|
|
||||||
# Get all modules that should have tests executed
|
# 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"
|
[ -z "${enabled_modules}" ] && enabled_modules="None"
|
||||||
|
|
||||||
# Get individual tests that should be executed
|
# 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