#!/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}/../..")" # shellcheck disable=SC1091 . "${SCRIPTDIR}/shdefaults" # shellcheck disable=SC1091 . "${TOPDIR}/utils/shfun" container_create() { local name=${1} local image=${2} shift 2 declare -a extra_opts readarray -t extra_opts < \ <(sed -e "s/-/--cap-drop=/g" -e "s/+/--cap-add=/g" \ <<< "$(printf '%s\n' "${CAP_DEFAULTS[@]}")") for opt in "$@" do [ -z "${opt}" ] && continue case "${opt}" in hostname=*) extra_opts+=("--${opt}") ;; cpus=*) extra_opts+=("--${opt}") ;; memory=*) extra_opts+=("--${opt}") ;; capabilities=*) extra_opts+=("--cap-add=${opt##*=}") ;; volume=*) extra_opts+=("--volume=${opt##*=}") ;; *) log error "container_create: Invalid option: ${opt}" ;; esac done # ensure default values are set [[ " ${extra_opts[*]} " =~ " --cpus=" ]] || extra_opts+=("--cpus=2") [[ " ${extra_opts[*]} " =~ " --hostname=" ]] \ || extra_opts+=("--hostname=ipaserver.test.local") log info "= Creating ${name} =" podman create \ --security-opt label=disable \ --network bridge:interface_name=eth0 \ --systemd true \ --name "${name}" \ --memory-swap -1 \ --no-hosts \ --replace \ "${extra_opts[@]}" \ "${image}" echo } container_start() { local name="${1}" log info "= Starting ${name} =" podman start "${name}" # Add host entry to /etc/hosts ip=$(podman inspect "${name}" --format "{{.NetworkSettings.IPAddress}}") hostname=$(podman inspect "${name}" --format "{{.Config.Hostname}}") if [ -n "${ip}" ] && [ -n "${hostname}" ]; then cmd=$(cat <> /etc/hosts EOF ) podman exec "${name}" bash -c "$cmd" fi # Ensure /etc/shadow is readable podman exec "${name}" bash -c "chmod u+r /etc/shadow" 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." } container_copy() { local name="${1}" local source="${2}" local destination="${3}" log info "= Copying ${source} to ${name}:${destination} =" podman cp "${source}" "${name}:${destination}" echo } container_fetch() { local name="${1}" local source="${2}" local destination="${3}" log info "= Copying ${name}:${source} to ${destination} =" podman cp "${name}:${source}" "${destination}" echo } container_tee() { local name=${1} local destination=${2} tmpfile=$(mktemp /tmp/container-temp.XXXXXX) log info "= Creating ${name}:${destination} from stdin =" cat - > "${tmpfile}" podman cp "${tmpfile}" "${name}:${destination}" rm "${tmpfile}" echo } container_save() { local name=${1} archive="${name}.tar" log info "= Saving ${name} to ${archive} =" # podman is not able to overwrite the archive [ -f "${archive}" ] && rm "${archive}" podman save -o "${archive}" "${name}" echo } container_load() { local name=${1} image_name=$(podman load -q -i "${name}" | sed -e "s/^Loaded image: //") image=$(podman image list -q "${image_name}") echo "$image" }