#!/bin/bash
#
# Pull docker images listed in DIB_TROVE_DOCKER_IMAGES directly into the
# image's containerd store using ctr, by running containerd inside the
# chroot (systemd is not running here). Instances then boot with the images
# fully extracted: no docker pull at instance create time, which in the
# gate runs on an emulated CPU and dominates instance provisioning time.
#
# Images are pulled into containerd's "moby" namespace, which is what Docker
# CE uses at boot (containerd.service + docker.service).
#
# Entries are space separated [source=]target references. When a source is
# given it is pulled and tagged as the target (used when the target name is
# not pullable at build time, e.g. a local registry only guests can reach).
#
# The dib chroot needs a self bind-mount of the containerd state root (the
# chroot root is not a mountpoint, so containerd's mountinfo lookups fail
# without it); undone on every exit path.
#
# When embedding was requested, it must work: any failure here fails the
# build. A silent fallback would produce an image that pulls at boot,
# reintroducing exactly the behaviour this element exists to remove.

if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then
    set -x
fi
set -eu
set -o pipefail

[ -z "${DIB_TROVE_DOCKER_IMAGES:-}" ] && exit 0

CONTAINERD_SOCK=/run/containerd/containerd.sock
CLOG=/tmp/dib-containerd.log
CONTAINERD_PID=""
BIND_MOUNTS=""
CTR="ctr -n moby"

stop_daemon() {
    local pid=$1
    if [ -n "${pid}" ] && kill -0 ${pid} 2>/dev/null; then
        kill ${pid}
        wait ${pid} 2>/dev/null || true
    fi
}

cleanup() {
    stop_daemon "${CONTAINERD_PID}"; CONTAINERD_PID=""
    rm -f ${CONTAINERD_SOCK}
    local m
    for m in ${BIND_MOUNTS}; do
        umount ${m} || true
    done
    BIND_MOUNTS=""
    :
}
trap cleanup EXIT

fail() {
    echo "ERROR: $*"
    echo "--- containerd log ---"
    cat ${CLOG} 2>/dev/null || true
    exit 1
}

setup_chroot_env() {
    # containerd's mountinfo lookups fail when the chroot root is not a
    # mountpoint; a self bind-mount makes /var/lib/containerd visible there.
    mkdir -p /var/lib/containerd
    mount --bind /var/lib/containerd /var/lib/containerd
    BIND_MOUNTS="/var/lib/containerd"
}

start_containerd() {
    mkdir -p $(dirname ${CONTAINERD_SOCK})
    containerd > ${CLOG} 2>&1 &
    CONTAINERD_PID=$!

    local i
    for i in $(seq 30); do
        [ -S ${CONTAINERD_SOCK} ] && return 0
        kill -0 ${CONTAINERD_PID} 2>/dev/null || return 1
        sleep 1
    done
    return 1
}

pull_image() {
    local ref=$1
    if ${CTR} images pull "${ref}"; then
        return 0
    fi
    echo "Retrying ${ref} with --plain-http (insecure local registry)"
    ${CTR} images pull --plain-http "${ref}"
}

setup_chroot_env
start_containerd || fail "containerd did not start in the chroot"

for entry in ${DIB_TROVE_DOCKER_IMAGES}; do
    source=${entry%%=*}
    target=${entry##*=}

    echo "Embedding docker image ${source} as ${target}"
    if ! pull_image "${source}"; then
        fail "unable to pull ${source} for embedding"
    fi
    if [ "${source}" != "${target}" ]; then
        if ! ${CTR} images tag "${source}" "${target}"; then
            fail "unable to tag ${source} as ${target}"
        fi
    fi
done

echo "Preloaded embedded docker images into the containerd image store"
