From d531c4a9807298a9d03406ec25015a9201997172 Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Mon, 16 Sep 2024 14:30:24 +0200 Subject: [PATCH 1/6] New infra/image/start.sh script to start the generated containers The script will try to get the latest image from quay to start it. With the -l option it will try to use a local image first. This is for example useful to test changes in the images build script locally. This also adds infra/image/shcontainer. Some of the content is copied from utils/shcontainer. --- infra/image/shcontainer | 161 ++++++++++++++++++++++++++++++++++++++++ infra/image/start.sh | 75 +++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 infra/image/shcontainer create mode 100755 infra/image/start.sh diff --git a/infra/image/shcontainer b/infra/image/shcontainer new file mode 100644 index 000000000..e3aa40c53 --- /dev/null +++ b/infra/image/shcontainer @@ -0,0 +1,161 @@ +#!/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 \ + --cap-add=SYS_ADMIN \ + --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 stop "${source}") + echo "${image}" +} + +container_image_list() { + local source="${1}" + + 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 000000000..0c1ab5943 --- /dev/null +++ b/infra/image/start.sh @@ -0,0 +1,75 @@ +#!/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 + +optional arguments: + + -l Try to use local image first, if not found download. + +EOF +} + +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:-} + +if [ -z "${image}" ]; then + die "Image needs to be given" +fi + +container_check + +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." From d6aa5cddf1a2e09ad5f52794fea7cb2b6f691259 Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Mon, 16 Sep 2024 14:39:28 +0200 Subject: [PATCH 2/6] infra/image/build.sh: Use new shcontainer This removes a lot of duplicate code from the script. --- infra/image/build.sh | 68 +++++++++++++------------------------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/infra/image/build.sh b/infra/image/build.sh index b16021740..dc6b992d8 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() { @@ -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 @@ -69,77 +72,46 @@ then [ -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}" - +container_remove_image_if_exists "${tag}" +[ "${deploy_server}" == "Y" ] && \ + container_remove_image_if_exists "${server_tag}" -log info "= Building ${tag} =" -podman build -t "${tag}" -f "${BASEDIR}/dockerfile/${distro}" \ - "${BASEDIR}" -echo - -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. =" From d0b18e36d6b9b5e9f8151b1d6ae14f65521b54ee Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Mon, 16 Sep 2024 14:11:24 +0200 Subject: [PATCH 3/6] Renamed infra/image/inventory to build-inventory, dropped interpreter This change also removed ansible_python_interpreter setting in the inventory as the interpreter should be discovered by ansible for the distributions. The dockerfiles have been adapted to not force the installation of python3 for CentOS-Stream 8, 9 and 10. --- infra/image/{inventory => build-inventory} | 2 +- infra/image/build.sh | 2 +- infra/image/dockerfile/c10s | 1 - infra/image/dockerfile/c8s | 2 -- infra/image/dockerfile/c9s | 1 - 5 files changed, 2 insertions(+), 6 deletions(-) rename infra/image/{inventory => build-inventory} (77%) diff --git a/infra/image/inventory b/infra/image/build-inventory similarity index 77% rename from infra/image/inventory rename to infra/image/build-inventory index 4a83eb75c..41f5feb60 100644 --- a/infra/image/inventory +++ b/infra/image/build-inventory @@ -1,5 +1,5 @@ [ipaserver] -ansible-freeipa-image-builder ansible_connection=podman ansible_python_interpreter=/usr/bin/python3 +ansible-freeipa-image-builder ansible_connection=podman [ipaserver:vars] ipaadmin_password=SomeADMINpassword diff --git a/infra/image/build.sh b/infra/image/build.sh index dc6b992d8..a17f2f6d1 100755 --- a/infra/image/build.sh +++ b/infra/image/build.sh @@ -68,7 +68,7 @@ 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 diff --git a/infra/image/dockerfile/c10s b/infra/image/dockerfile/c10s index 622098f36..18d481475 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 \ diff --git a/infra/image/dockerfile/c8s b/infra/image/dockerfile/c8s index 87a5b82e6..a59879f1e 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 \ diff --git a/infra/image/dockerfile/c9s b/infra/image/dockerfile/c9s index 5fe77d926..5897d9ff4 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 \ From 02fb822d95bd6f66112732d2ce772095c7759c3c Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Mon, 16 Sep 2024 14:22:25 +0200 Subject: [PATCH 4/6] Use container-ipa.target from freeipa-container container project This reduces the number of started services in the container. The fixipaip.service needed to be adapted to ensure that the service is started properly. The dockerfiles have been adapted for this change also. --- infra/image/dockerfile/c10s | 13 +++++++++++++ infra/image/dockerfile/c8s | 13 +++++++++++++ infra/image/dockerfile/c9s | 13 +++++++++++++ infra/image/dockerfile/fedora-latest | 13 +++++++++++++ infra/image/dockerfile/fedora-rawhide | 13 +++++++++++++ infra/image/system-service/container-ipa.target | 6 ++++++ infra/image/system-service/fixipaip.service | 2 +- 7 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 infra/image/system-service/container-ipa.target diff --git a/infra/image/dockerfile/c10s b/infra/image/dockerfile/c10s index 18d481475..3710cdc02 100644 --- a/infra/image/dockerfile/c10s +++ b/infra/image/dockerfile/c10s @@ -12,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 a59879f1e..3cf629a04 100644 --- a/infra/image/dockerfile/c8s +++ b/infra/image/dockerfile/c8s @@ -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/dockerfile/c9s b/infra/image/dockerfile/c9s index 5897d9ff4..daf181c40 100644 --- a/infra/image/dockerfile/c9s +++ b/infra/image/dockerfile/c9s @@ -12,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 aadcffb75..f286f9f9e 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 5a1aa005c..b726489ef 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/system-service/container-ipa.target b/infra/image/system-service/container-ipa.target new file mode 100644 index 000000000..c8538814f --- /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 95db11808..ec56c0d44 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 From b2953170366656e021b0af069118d033eb93c7fd Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Mon, 16 Sep 2024 14:26:39 +0200 Subject: [PATCH 5/6] infra/image/build.sh: "-s" help fix and cleanup The help has been fixed for the -s option and the comments about how to start the container later on has been removed as there will be a script that is handling this.. --- infra/image/build.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/infra/image/build.sh b/infra/image/build.sh index a17f2f6d1..6da817919 100755 --- a/infra/image/build.sh +++ b/infra/image/build.sh @@ -15,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 } @@ -38,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" @@ -115,9 +115,3 @@ then 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}" From 1882a1c771f0468cea8e2db6d89dfce322a25c31 Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Mon, 16 Sep 2024 14:23:31 +0200 Subject: [PATCH 6/6] infra/image/system-service/fixipaip.sh: Behave idempotent This makes sure that the service is not failing on already applied modifications. --- infra/image/system-service/fixipaip.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/infra/image/system-service/fixipaip.sh b/infra/image/system-service/fixipaip.sh index f7053e029..ed11a2b6a 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