From 691e5915b9ecb350918acaecc2d052f8f88d7ecd Mon Sep 17 00:00:00 2001
From: Thomas Woerner <twoerner@redhat.com>
Date: Mon, 16 Sep 2024 14:30:24 +0200
Subject: [PATCH] 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 | 166 ++++++++++++++++++++++++++++++++++++++++
 infra/image/start.sh    |  87 +++++++++++++++++++++
 2 files changed, 253 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 0000000..6f4e8a8
--- /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 0000000..c5a7a34
--- /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."
-- 
GitLab