diff --git a/infra/image/build-inventory b/infra/image/build-inventory new file mode 100644 index 0000000000000000000000000000000000000000..41f5feb608926a10d00ea456810a2acd982a5549 --- /dev/null +++ b/infra/image/build-inventory @@ -0,0 +1,15 @@ +[ipaserver] +ansible-freeipa-image-builder ansible_connection=podman + +[ipaserver:vars] +ipaadmin_password=SomeADMINpassword +ipadm_password=SomeDMpassword +ipaserver_domain=test.local +ipaserver_realm=TEST.LOCAL +ipaserver_setup_dns=true +ipaserver_auto_forwarders=true +ipaserver_no_dnssec_validation=true +ipaserver_auto_reverse=true +ipaserver_setup_kra=true +ipaserver_setup_firewalld=false +ipaclient_no_ntp=true diff --git a/infra/image/build.sh b/infra/image/build.sh index b16021740b3443fcd91c548da0a2259df2f25827..6da8179191b519aad1bda828b347b428bdb3c6b1 100755 --- a/infra/image/build.sh +++ b/infra/image/build.sh @@ -3,6 +3,9 @@ BASEDIR="$(readlink -f "$(dirname "$0")")" TOPDIR="$(readlink -f "${BASEDIR}/../..")" +# shellcheck disable=SC1091 +. "${BASEDIR}/shcontainer" +# shellcheck disable=SC1091 . "${TOPDIR}/utils/shfun" valid_distro() { @@ -12,7 +15,7 @@ valid_distro() { usage() { local prog="${0##*/}" cat << EOF -usage: ${prog} [-h] [i] distro +usage: ${prog} [-h] [-s] distro ${prog} build a container image to test ansible-freeipa. EOF } @@ -35,7 +38,7 @@ name="ansible-freeipa-image-builder" hostname="ipaserver.test.local" # Number of cpus is not available in usptream CI (Ubuntu 22.04). # cpus="2" -memory="4g" +memory="3g" quayname="quay.io/ansible-freeipa/upstream-tests" deploy_server="N" @@ -56,7 +59,7 @@ distro=${1:-} [ -f "${BASEDIR}/dockerfile/${distro}" ] \ || die "${distro} is not a valid distro target.\nUse one of: $(valid_distro)" -[ -n "$(command -v "podman")" ] || die "podman is required." +container_check if [ "${deploy_server}" == "Y" ] then @@ -65,87 +68,50 @@ then deploy_playbook="${TOPDIR}/playbooks/install-server.yml" [ -f "${deploy_playbook}" ] || die "Can't find playbook '${deploy_playbook}'" - inventory_file="${BASEDIR}/inventory" + inventory_file="${BASEDIR}/build-inventory" [ -f "${inventory_file}" ] || die "Can't find inventory '${inventory_file}'" fi -container_state="$(podman ps -q --all --format "{{.State}}" --filter "name=${name}")" +container_state=$(container_get_state "${name}") tag="${distro}-base" server_tag="${distro}-server" -# in older (as in Ubuntu 22.04) podman versions, -# 'podman image rm --force' fails if the image -# does not exist. -remove_image_if_exists() -{ - local tag_to_remove - tag_to_remove="${1}" - if podman image exists "${tag_to_remove}" - then - log info "= Cleanup ${tag_to_remove} =" - podman image rm "${tag_to_remove}" --force - echo - fi -} - -remove_image_if_exists "${tag}" -[ "${deploy_server}" == "Y" ] && remove_image_if_exists "${server_tag}" - - -log info "= Building ${tag} =" -podman build -t "${tag}" -f "${BASEDIR}/dockerfile/${distro}" \ - "${BASEDIR}" -echo +container_remove_image_if_exists "${tag}" +[ "${deploy_server}" == "Y" ] && \ + container_remove_image_if_exists "${server_tag}" -log info "= Creating ${name} =" -podman create --privileged --name "${name}" --hostname "${hostname}" \ - --network bridge:interface_name=eth0 --systemd true \ - --memory "${memory}" --memory-swap -1 --no-hosts \ - --replace "${tag}" -echo - -log info "= Committing \"${quayname}:${tag}\" =" -podman commit "${name}" "${quayname}:${tag}" -echo +container_build "${tag}" "${BASEDIR}/dockerfile/${distro}" "${BASEDIR}" +container_create "${name}" "${tag}" "${hostname}" "${memory}" +container_commit "${name}" "${quayname}:${tag}" if [ "${deploy_server}" == "Y" ] then deployed=false - log info "= Starting ${name} =" - [ "${container_state}" == "running" ] || podman start "${name}" - echo + [ "${container_state}" != "running" ] && container_start "${name}" + + container_wait_for_journald "${name}" log info "= Deploying IPA =" - if ansible-playbook -i "${inventory_file}" "${deploy_playbook}" + if ansible-playbook -u root -i "${inventory_file}" "${deploy_playbook}" then deployed=true fi echo if $deployed; then - log info "= Enabling additional services =" - podman exec "${name}" systemctl enable fixnet - podman exec "${name}" systemctl enable fixipaip + log info "= Enabling services =" + container_exec "${name}" systemctl enable fixnet + container_exec "${name}" systemctl enable fixipaip echo fi - log info "= Stopping container ${name} =" - podman stop "${name}" - echo + container_stop "${name}" $deployed || die "Deployment failed" - log info "= Committing \"${quayname}:${server_tag}\" =" - podman commit "${name}" "${quayname}:${server_tag}" - echo + container_commit "${name}" "${quayname}:${server_tag}" fi log info "= DONE: Image created. =" - -# For tests: -# podman start "${name}" -# while [ -n "$(podman exec ansible-test systemctl list-jobs | grep -vi "no jobs running")" ]; do echo "waiting.."; sleep 5; done -# # Run tests -# podman stop "${name}" diff --git a/infra/image/dockerfile/c10s b/infra/image/dockerfile/c10s index 622098f36b7cb84b2772ba6dfa17810c6720bf01..3710cdc0269c4d260db4d71c51fb9f2fa54e941d 100644 --- a/infra/image/dockerfile/c10s +++ b/infra/image/dockerfile/c10s @@ -4,7 +4,6 @@ ENV container=podman RUN rm -fv /var/cache/dnf/metadata_lock.pid; \ dnf makecache; \ dnf --assumeyes install \ - /usr/bin/python3 \ /usr/bin/dnf-3 \ sudo \ bash \ @@ -13,6 +12,19 @@ dnf --assumeyes install \ iproute; \ rm -rf /var/cache/dnf/; +RUN (cd /lib/systemd/system/; \ + if [ -e dbus-broker.service ] && [ ! -e dbus.service ]; then \ + ln -s dbus-broker.service dbus.service; \ + fi \ +) +COPY system-service/container-ipa.target /lib/systemd/system/ +RUN systemctl set-default container-ipa.target +RUN (cd /etc/systemd/system/; \ + rm -rf multi-user.target.wants \ + && mkdir container-ipa.target.wants \ + && ln -s container-ipa.target.wants multi-user.target.wants \ +) + COPY system-service/fixnet.sh /root/ COPY system-service/fixipaip.sh /root/ COPY system-service/fixnet.service /etc/systemd/system/ diff --git a/infra/image/dockerfile/c8s b/infra/image/dockerfile/c8s index 87a5b82e685258dab30c53ebbd5283adab7b7adc..3cf629a044bed33c15a91a2ba6979454b9295fc7 100644 --- a/infra/image/dockerfile/c8s +++ b/infra/image/dockerfile/c8s @@ -7,8 +7,6 @@ sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo; \ sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo; \ dnf makecache; \ dnf --assumeyes install \ - /usr/bin/python3 \ - /usr/bin/python3-config \ /usr/bin/dnf-3 \ sudo \ bash \ @@ -18,6 +16,19 @@ dnf --assumeyes install \ dnf clean all; \ rm -rf /var/cache/dnf/; +RUN (cd /lib/systemd/system/; \ + if [ -e dbus-broker.service ] && [ ! -e dbus.service ]; then \ + ln -s dbus-broker.service dbus.service; \ + fi \ +) +COPY system-service/container-ipa.target /lib/systemd/system/ +RUN systemctl set-default container-ipa.target +RUN (cd /etc/systemd/system/; \ + rm -rf multi-user.target.wants \ + && mkdir container-ipa.target.wants \ + && ln -s container-ipa.target.wants multi-user.target.wants \ +) + COPY system-service/fixnet.sh /root/ COPY system-service/fixipaip.sh /root/ COPY system-service/fixnet.service /etc/systemd/system/ diff --git a/infra/image/dockerfile/c9s b/infra/image/dockerfile/c9s index 5fe77d926732c871a71e134cf0adfa3fb8883c14..daf181c40f2296da585cdf75bdfd86f01526f49c 100644 --- a/infra/image/dockerfile/c9s +++ b/infra/image/dockerfile/c9s @@ -4,7 +4,6 @@ ENV container=podman RUN rm -fv /var/cache/dnf/metadata_lock.pid; \ dnf makecache; \ dnf --assumeyes install \ - /usr/bin/python3 \ /usr/bin/dnf-3 \ sudo \ bash \ @@ -13,6 +12,19 @@ dnf --assumeyes install \ iproute; \ rm -rf /var/cache/dnf/; +RUN (cd /lib/systemd/system/; \ + if [ -e dbus-broker.service ] && [ ! -e dbus.service ]; then \ + ln -s dbus-broker.service dbus.service; \ + fi \ +) +COPY system-service/container-ipa.target /lib/systemd/system/ +RUN systemctl set-default container-ipa.target +RUN (cd /etc/systemd/system/; \ + rm -rf multi-user.target.wants \ + && mkdir container-ipa.target.wants \ + && ln -s container-ipa.target.wants multi-user.target.wants \ +) + COPY system-service/fixnet.sh /root/ COPY system-service/fixipaip.sh /root/ COPY system-service/fixnet.service /etc/systemd/system/ diff --git a/infra/image/dockerfile/fedora-latest b/infra/image/dockerfile/fedora-latest index aadcffb7506c1edac65f7ae3a3db5d3e5c8d391d..f286f9f9e894a9ce1c2af59677a535f0e72a4ba1 100644 --- a/infra/image/dockerfile/fedora-latest +++ b/infra/image/dockerfile/fedora-latest @@ -15,6 +15,19 @@ dnf --assumeyes install \ dnf clean all; \ rm -rf /var/cache/dnf/; +RUN (cd /lib/systemd/system/; \ + if [ -e dbus-broker.service ] && [ ! -e dbus.service ]; then \ + ln -s dbus-broker.service dbus.service; \ + fi \ +) +COPY system-service/container-ipa.target /lib/systemd/system/ +RUN systemctl set-default container-ipa.target +RUN (cd /etc/systemd/system/; \ + rm -rf multi-user.target.wants \ + && mkdir container-ipa.target.wants \ + && ln -s container-ipa.target.wants multi-user.target.wants \ +) + COPY system-service/fixnet.sh /root/ COPY system-service/fixipaip.sh /root/ COPY system-service/fixnet.service /etc/systemd/system/ diff --git a/infra/image/dockerfile/fedora-rawhide b/infra/image/dockerfile/fedora-rawhide index 5a1aa005cdfa4f19bdcc176fb96a02f24667da54..b726489efadb5974ea69e834b44e198c45cf876f 100644 --- a/infra/image/dockerfile/fedora-rawhide +++ b/infra/image/dockerfile/fedora-rawhide @@ -16,6 +16,19 @@ dnf --assumeyes install \ dnf clean all; \ rm -rf /var/cache/dnf/; +RUN (cd /lib/systemd/system/; \ + if [ -e dbus-broker.service ] && [ ! -e dbus.service ]; then \ + ln -s dbus-broker.service dbus.service; \ + fi \ +) +COPY system-service/container-ipa.target /lib/systemd/system/ +RUN systemctl set-default container-ipa.target +RUN (cd /etc/systemd/system/; \ + rm -rf multi-user.target.wants \ + && mkdir container-ipa.target.wants \ + && ln -s container-ipa.target.wants multi-user.target.wants \ +) + COPY system-service/fixnet.sh /root/ COPY system-service/fixipaip.sh /root/ COPY system-service/fixnet.service /etc/systemd/system/ diff --git a/infra/image/inventory b/infra/image/inventory index 4a83eb75ccf7e07e6b5efd2acdbbd2c082b5a5a5..043fab0d0697d8a64bd48550dbb750282ec1c3ac 100644 --- a/infra/image/inventory +++ b/infra/image/inventory @@ -1,15 +1,6 @@ [ipaserver] -ansible-freeipa-image-builder ansible_connection=podman ansible_python_interpreter=/usr/bin/python3 +ansible-freeipa-tests ansible_connection=podman [ipaserver:vars] ipaadmin_password=SomeADMINpassword ipadm_password=SomeDMpassword -ipaserver_domain=test.local -ipaserver_realm=TEST.LOCAL -ipaserver_setup_dns=true -ipaserver_auto_forwarders=true -ipaserver_no_dnssec_validation=true -ipaserver_auto_reverse=true -ipaserver_setup_kra=true -ipaserver_setup_firewalld=false -ipaclient_no_ntp=true diff --git a/infra/image/shcontainer b/infra/image/shcontainer new file mode 100644 index 0000000000000000000000000000000000000000..6f4e8a85272b91c51394cc3f222c23c0e3ebdd59 --- /dev/null +++ b/infra/image/shcontainer @@ -0,0 +1,166 @@ +#!/bin/bash -eu +# This file is meant to be source'd by other scripts + +SCRIPTDIR="$(dirname -- "$(readlink -f "${BASH_SOURCE[0]}")")" +TOPDIR="$(readlink -f "${SCRIPTDIR}/../..")" + +. "${TOPDIR}/utils/shfun" + +container_create() { + local name=${1} + local image=${2} + local hostname=${3} + local memory=${4:-"3g"} + local cpus=${5:-"2"} + + [ -n "${hostname}" ] || die "No hostname given" + + log info "= Creating ${name} =" + podman create \ + --security-opt label=disable \ + --name "${name}" \ + --hostname "${hostname}" \ + --network bridge:interface_name=eth0 \ + --systemd true \ + --cpus "${cpus}" \ + --memory "${memory}" \ + --memory-swap -1 \ + --no-hosts \ + --replace \ + "${image}" + echo +} + +container_start() { + local name="${1}" + + log info "= Starting ${name} =" + podman start "${name}" + echo +} + +container_stop() { + local name="${1}" + + log info "= Stopping ${name} =" + podman stop "${name}" + echo +} + +container_wait_for_journald() { + local name=${1} + + log info "= Waiting till systemd-journald is running =" + max=20 + wait=2 + count=0 + while ! podman exec "${name}" ps -x | grep -q "systemd-journald" + do + if [ $count -ge $max ]; then + die "Timeout: systemd-journald is not starting up" + fi + count=$((count+1)) + log info "Waiting ${wait} seconds .." + sleep ${wait} + done + log info "done" + echo +} + +container_wait_up() { + local name="${1}" + + log info "= Waiting till all services are started =" + max=20 + wait=15 + count=0 + while podman exec "${name}" systemctl list-jobs | \ + grep -qvi "no jobs running" + do + if [ $count -ge $max ]; then + die "Timeout: Services are not starting up" + fi + count=$((count+1)) + log info "Waiting ${wait} seconds .." + sleep ${wait} + done + log info "done" + echo +} + +container_build() { + local tag="${1}" + local file="${2}" + local dir="${3}" + + log info "= Building ${tag} =" + podman build -t "${tag}" -f "${file}" "${dir}" + echo +} + +container_commit() { + local name="${1}" + local image="${2}" + + log info "= Committing \"${image}\" =" + podman commit "${name}" "${image}" + echo +} + +container_exec() { + local name="${1}" + shift 1 + + # "@Q" is only needed for the log output, the exec command is properly + # working without also for args containing spaces. + log info "= Executing \"${*@Q}\" =" + podman exec -t "${name}" "${@}" + echo +} + +container_remove_image_if_exists() +{ + # In older (as in Ubuntu 22.04) podman versions, + # 'podman image rm --force' fails if the image + # does not exist. + local tag_to_remove="${1}" + + if podman image exists "${tag_to_remove}" + then + log info "= Cleanup ${tag_to_remove} =" + podman image rm "${tag_to_remove}" --force + echo + fi +} + +container_get_state() +{ + local name="${1}" + + state=$(podman ps -q --all --format "{{.State}}" --filter "name=${name}") + echo "${state}" +} + +container_pull() { + local source="${1}" + + image=$(podman pull "${source}") + echo "${image}" +} + +container_image_list() { + local source="${1}" + + # Append "$" for an exact match if the source does not end with ":" to + # search for the repo only. + if [[ ${source} != *: ]]; then + source="${source}$" + fi + image=$(podman image list --format "{{ .Repository }}:{{ .Tag }}" | \ + grep "^${source}") + echo "${image}" +} + +container_check() { + [ -n "$(command -v "podman")" ] || die "podman is required." +} diff --git a/infra/image/start.sh b/infra/image/start.sh new file mode 100755 index 0000000000000000000000000000000000000000..c5a7a342863cd882f62d3b6dca313568b8ce7606 --- /dev/null +++ b/infra/image/start.sh @@ -0,0 +1,87 @@ +#!/bin/bash -eu + +BASEDIR="$(readlink -f "$(dirname "$0")")" +TOPDIR="$(readlink -f "${BASEDIR}/../..")" + +# shellcheck disable=SC1091 +. "${BASEDIR}/shcontainer" +# shellcheck disable=SC1091 +. "${TOPDIR}/utils/shfun" + +usage() { + local prog="${0##*/}" + cat << EOF +usage: ${prog} [-h] [-l] image + ${prog} start a prebuilt ansible-freeipa test container image. +EOF +} + +help() { + cat << EOF +positional arguments: + + image The image to start, leave empty to get list of images + +optional arguments: + + -l Try to use local image first, if not found download. + +EOF +} + +list_images() { + local quay_api="https://quay.io/api/v1/repository/ansible-freeipa/upstream-tests/tag" + log info "Available images on quay:" + curl --silent -L "${quay_api}" | jq '.tags[]|.name' | tr -d '"'| sort | uniq | sed "s/.*/ &/" + echo + log info "Local images (use -l):" + local_image=$(container_image_list "${repo}:") + echo "${local_image}" | sed -e "s/.*://" | sed "s/.*/ &/" + echo +} + +repo="quay.io/ansible-freeipa/upstream-tests" +name="ansible-freeipa-tests" +hostname="ipaserver.test.local" +try_local_first="N" + +while getopts ":hl" option +do + case "${option}" in + h) help && exit 0 ;; + l) try_local_first="Y" ;; + *) die -u "Invalid option: ${option}" ;; + esac +done + +shift $((OPTIND - 1)) +image=${1:-} + +container_check + +if [ -z "${image}" ]; then + list_images + exit 0 +fi + +local_image= +if [ "${try_local_first}" == "Y" ]; then + log info "= Trying to use local image first =" + local_image=$(container_image_list "${repo}:${image}") + [ -n "${local_image}" ] && log info "Found ${local_image}" + echo +fi +if [ -z "${local_image}" ]; then + log info "= Downloading from quay =" + local_image=$(container_pull "${repo}:${image}") + echo +fi + +[ -z "${local_image}" ] && die "Image '${image}' is not valid" + +container_create "${name}" "${local_image}" "${hostname}" +container_start "${name}" +container_wait_for_journald "${name}" +container_wait_up "${name}" + +log info "Container ${name} is ready to be used." diff --git a/infra/image/system-service/container-ipa.target b/infra/image/system-service/container-ipa.target new file mode 100644 index 0000000000000000000000000000000000000000..c8538814fb9e60c6d94239f2cb85b31f86f78de7 --- /dev/null +++ b/infra/image/system-service/container-ipa.target @@ -0,0 +1,6 @@ +[Unit] +Description=Minimal target for containerized FreeIPA server +DefaultDependencies=false +AllowIsolate=yes +Requires=systemd-tmpfiles-setup.service systemd-journald.service dbus.service +After=systemd-tmpfiles-setup.service systemd-journald.service dbus.service diff --git a/infra/image/system-service/fixipaip.service b/infra/image/system-service/fixipaip.service index 95db1180825ddc93b60d65fbf6778587cb36b6c4..ec56c0d44fae4b9405d3726e583f2c1639701596 100644 --- a/infra/image/system-service/fixipaip.service +++ b/infra/image/system-service/fixipaip.service @@ -1,6 +1,6 @@ [Unit] Description=Fix IPA server IP in IPA Server -After=multi-user.target +After=ipa.service [Service] Type=oneshot diff --git a/infra/image/system-service/fixipaip.sh b/infra/image/system-service/fixipaip.sh index f7053e0292334e6861244034cfa88f2b87215fde..ed11a2b6a4a36c8f88f15926f139c2170d2a4235 100755 --- a/infra/image/system-service/fixipaip.sh +++ b/infra/image/system-service/fixipaip.sh @@ -73,16 +73,16 @@ for zone in ${ZONES}; do echo "ERROR: Failed to get old PTR from '${zone}': '${OLD_PTR}'" else ipa dnsrecord-mod "${zone}" "${OLD_PTR}" --ptr-rec="${HOSTNAME}." \ - --rename="${PTR}" + --rename="${PTR}" || true fi else echo "Fixing forward zone ${zone}:" - ipa dnsrecord-mod test.local "${HOSTNAME%%.*}" --a-rec="$IP" - ipa dnsrecord-mod test.local ipa-ca --a-rec="$IP" + ipa dnsrecord-mod test.local "${HOSTNAME%%.*}" --a-rec="$IP" || true + ipa dnsrecord-mod test.local ipa-ca --a-rec="$IP" || true fi done -ipa dnsserver-mod "${HOSTNAME}" --forwarder="${FORWARDER}" +ipa dnsserver-mod "${HOSTNAME}" --forwarder="${FORWARDER}" || true kdestroy -c "${KRB5CCNAME}" -A