mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-26 21:33:05 +00:00
This patch allows local execution of playbook tests using ustream CI testing images. Either 'podman' or 'docker' can be used to execute the tests.
401 lines
11 KiB
Bash
Executable File
401 lines
11 KiB
Bash
Executable File
#!/bin/bash -eu
|
|
|
|
trap interrupt_exception SIGINT
|
|
|
|
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
|
|
}
|
|
|
|
usage() {
|
|
local prog="${0##*/}"
|
|
cat <<EOF
|
|
usage: ${prog} [-h] [-l] [-e] [-g] [-s TESTS_SUITE] [-i IMAGE] [TEST...]
|
|
${prog} runs playbook(s) TEST using an ansible-freeipa testing image.
|
|
|
|
EOF
|
|
}
|
|
|
|
help() {
|
|
usage
|
|
echo -e "$(cat <<EOF
|
|
positional arguments:
|
|
TEST A list of playbook tests to be executed.
|
|
Either a TEST or a MODULE must be provided.
|
|
|
|
optional arguments:
|
|
-h display this message and exit
|
|
-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 select image to run the tests (default: fedora-latest)
|
|
-m container memory, in GiB (default: 3)
|
|
-s TEST_SUITE run all playbooks for test suite, which is a directory
|
|
under ${WHITE}tests${RST}
|
|
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>=2.12,<2.13'}
|
|
verbose=""
|
|
FORCE_ENV="N"
|
|
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"
|
|
IMAGE_TAG="fedora-latest"
|
|
scenario=""
|
|
MEMORY=3
|
|
hostname="ipaserver.test.local"
|
|
|
|
ANSIBLE_COLLECTIONS=${ANSIBLE_COLLECTIONS:-"containers.podman"}
|
|
|
|
# Process command options
|
|
|
|
while getopts ":hc:ei:Klms:v" option
|
|
do
|
|
case "$option" in
|
|
h) help && exit 0 ;;
|
|
c) scenario="${OPTARG}" ;;
|
|
e) FORCE_ENV="Y" ;;
|
|
i) IMAGE_TAG="${OPTARG}" ;;
|
|
K) STOP_CONTAINER="N" ;;
|
|
l) list_images && exit 0 || exit 1;;
|
|
m) MEMORY="${OPTARG}" ;;
|
|
s)
|
|
if [ -d "${TOPDIR}/tests/${OPTARG}" ]
|
|
then
|
|
ENABLED_MODULES+=("${OPTARG}")
|
|
else
|
|
log error "Invalid suite: ${OPTARG}"
|
|
fi
|
|
;;
|
|
v) verbose=${verbose:--}${option} ;;
|
|
*) die -u "Invalid option: ${OPTARG}" ;;
|
|
esac
|
|
done
|
|
|
|
for test in "${@:${OPTIND}}"
|
|
do
|
|
# shellcheck disable=SC2207
|
|
if stat "$test" >/dev/null 2>&1
|
|
then
|
|
ENABLED_TESTS+=($(basename "${test}" .yml))
|
|
else
|
|
log error "Test not found: ${test}"
|
|
fi
|
|
done
|
|
|
|
[ ${#ENABLED_MODULES[@]} -eq 0 ] && [ ${#ENABLED_TESTS[@]} -eq 0 ] && die -u "No test defined."
|
|
|
|
# Prepare virtual environment
|
|
VENV=$(in_python_virtualenv && echo Y || echo N)
|
|
|
|
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}"
|
|
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
|
|
else
|
|
log info "Using current virtual environment."
|
|
fi
|
|
|
|
# Ansible configuration
|
|
export ANSIBLE_ROLES_PATH="${TOPDIR}/roles"
|
|
export ANSIBLE_LIBRARY="${TOPDIR}/plugins:${TOPDIR}/molecule"
|
|
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
|
|
|
|
|
|
# run tests
|
|
RESULT=0
|
|
# shellcheck disable=SC2086
|
|
export RUN_TESTS_IN_DOCKER=${engine}
|
|
export IPA_SERVER_HOST="${scenario}"
|
|
joined="$(printf "%s," "${ENABLED_MODULES[@]}")"
|
|
# shelcheck disable=SC2178
|
|
IPA_ENABLED_MODULES="${joined%,}"
|
|
joined="$(printf "%s," "${ENABLED_TESTS[@]}")"
|
|
# shelcheck disable=SC2178
|
|
IPA_ENABLED_TESTS="${joined%,}"
|
|
export IPA_ENABLED_MODULES IPA_ENABLED_TESTS
|
|
[ -n "${IPA_ENABLED_MODULES}" ] && log info "Test suites: ${IPA_ENABLED_MODULES}"
|
|
[ -n "${IPA_ENABLED_TESTS}" ] && log info "Individual tests: ${IPA_ENABLED_TESTS}"
|
|
|
|
IPA_VERBOSITY="${verbose}"
|
|
[ -n "${IPA_VERBOSITY}" ] && export IPA_VERBOSITY
|
|
|
|
if ! pytest -m "playbook" --verbose --color=yes
|
|
then
|
|
RESULT=2
|
|
log error "Container not stopped for verification: ${scenario}"
|
|
log info "Container: $(podman ps -f "id=${container_id}" --format "{{.Names}} - {{.ID}}")"
|
|
fi
|
|
[ -z "${CONTINUE_ON_ERROR}" ] && [ $RESULT -ne 0 ] && die "Stopping on test failure."
|
|
|
|
# cleanup environment
|
|
cleanup "${scenario}" "${engine}"
|