#!/usr/bin/bash
set -eo pipefail

trap cleanup EXIT

# Defaults
REGISTRY=registry.redhat.io
IMAGE=rhel9/support-tools
AUTHFILE=/var/lib/kubelet/config.json
TOOLBOX_NAME=toolbox-"$(whoami)"
TOOLBOXRC="${HOME}"/.toolboxrc

errecho() {
    >&2 echo "${@}"
}

setup() {
    # Allow user overrides
    if [ -f "${TOOLBOXRC}" ]; then
        errecho ".toolboxrc file detected, overriding defaults..."
        source "${TOOLBOXRC}"
    fi
    TOOLBOX_IMAGE="${REGISTRY}"/"${IMAGE}"
}

run() {
    # Pull the container image if it does not exists yet
    if ! image_exists; then
        image_pull
        if container_exists; then
            sudo podman rm "${TOOLBOX_NAME}"
        fi
    # If it already exists, make sure it is up-to-date
    elif ! image_fresh; then
        >&2 read -r -p "There is a newer version of ${TOOLBOX_IMAGE} available. Would you like to pull it? [y/N] "
        if [[ ${REPLY} =~ ^([Yy][Ee][Ss]|[Yy])+$ ]]; then
            image_pull
            if container_exists; then
                sudo podman rm "${TOOLBOX_NAME}"
            fi
        else
            errecho "Skipping retrieval of new image.."
        fi
    fi

    # If the container does not already exists, create it, while making sure to
    # use the option from the RUN label if provided
    local runlabel=$(image_runlabel)
    if ! container_exists; then
        errecho "Spawning a container '${TOOLBOX_NAME}' with image '${TOOLBOX_IMAGE}'"
        if [[ -z "${runlabel}" ]] || [[ "${runlabel}" == "<no value>" ]]; then
            container_create
        else
            errecho "Detected RUN label in the container image. Using that as the default..."
            container_create_runlabel
        fi
    else
        errecho "Container '${TOOLBOX_NAME}' already exists. Trying to start..."
        errecho "(To remove the container and start with a fresh toolbox, run: sudo podman rm '${TOOLBOX_NAME}')"
    fi

    # Start our freshly created container
    local state=$(container_state)
    if [[ "${state}" == configured ]] || [[ "${state}" == created ]] || [[ "${state}" == exited ]] || [[ "${state}" == stopped ]]; then
        container_start
    elif [[ "${state}" != running ]]; then
        errecho "Container '${TOOLBOX_NAME}' in unknown state: '$state'"
        return 1
    fi

    if [[ "$#" -eq "0" ]]; then
        errecho "Container started successfully. To exit, type 'exit'."
    fi
    # Attach to the interactive shell in the container or directly execute the
    # command passed as argument
    container_exec "$@"
}

cleanup() {
    sudo podman stop "${TOOLBOX_NAME}" &>/dev/null
}

container_exists() {
    sudo podman container inspect "${TOOLBOX_NAME}" &>/dev/null
}

container_state() {
    sudo podman container inspect "${TOOLBOX_NAME}" --format '{{.State.Status}}'
}

image_exists() {
    sudo podman image inspect "${TOOLBOX_IMAGE}" &>/dev/null
}

# returns 0 if the image on disk is "fresh", i.e. no newer image on remote
# registry. (or if we couldn't inspect the registry successfully)
image_fresh() {
    errecho "Checking if there is a newer version of ${TOOLBOX_IMAGE} available..."
    local_date=$(sudo podman image inspect "${TOOLBOX_IMAGE}" --format '{{.Created}}')

    if ! remote_date=$(sudo --preserve-env skopeo inspect --authfile "${AUTHFILE}" docker://"${TOOLBOX_IMAGE}" --format '{{.Created}}'); then
        errecho "Error inspecting ${TOOLBOX_IMAGE} via skopeo"
        return
    fi
    # if the date on the registry is *NOT* newer than the local image date
    # then we return 1. (doing a less-than comparison of the strings always
    # fails if they are the same, hence the weird conditional here)
    ! [[ "${remote_date}" > "${local_date}" ]]
}

image_runlabel() {
    sudo podman image inspect "${TOOLBOX_IMAGE}" --format '{{- if index .Labels "run" -}}{{.Labels.run}}{{- end -}}'
}


image_pull() {
    if ! sudo --preserve-env podman pull --authfile "${AUTHFILE}" "${TOOLBOX_IMAGE}"; then
        >&2 read -r -p "Would you like to manually authenticate to registry: '${REGISTRY}' and try again? [y/N] "

        if [[ ${REPLY} =~ ^([Yy][Ee][Ss]|[Yy])+$ ]]; then
            sudo --preserve-env podman login --authfile "${AUTHFILE}" "${REGISTRY}"
            sudo --preserve-env podman pull --authfile "${AUTHFILE}" "${TOOLBOX_IMAGE}"
        else
            errecho "Exiting..."
            exit 1
        fi
    fi
}

container_create() {
    local -r cmd=$(sudo podman image inspect "${TOOLBOX_IMAGE}" | jq -re ".[].Config.Cmd[0]") || cmd="/bin/sh"
    if ! sudo podman create \
        --hostname toolbox \
        --name "${TOOLBOX_NAME}" \
        --privileged \
        --net=host \
        --pid=host \
        --ipc=host \
        --tty \
        --interactive \
        --env HOST=/host \
        --env NAME="${TOOLBOX_NAME}" \
        --env IMAGE="${IMAGE}" \
        --security-opt label=disable \
        --volume /run:/run \
        --volume /var/log:/var/log \
        --volume /etc/machine-id:/etc/machine-id \
        --volume /etc/localtime:/etc/localtime \
        --volume /:/host \
        "${TOOLBOX_IMAGE}" "${cmd}"; then
        errecho "$0: failed to create container '${TOOLBOX_NAME}'"
        exit 1
    fi
}

container_start() {
    if ! sudo podman start "${TOOLBOX_NAME}"; then
        errecho "$0: failed to start container '${TOOLBOX_NAME}'"
        exit 1
    fi
}

container_create_runlabel() {
    # Variable replacement logic reproduced from:
    # https://github.com/containers/podman/blob/29d7ab3f82e38c442e449739e218349b9a4a16ea/pkg/domain/infra/abi/containers_runlabel.go#L226
    local pod
    pod="$(echo "${runlabel}" \
        | sed 's/podman run/sudo podman create/' \
        | sed 's/--name NAME/--name ${TOOLBOX_NAME}/' \
        | sed 's/NAME=NAME/NAME=${TOOLBOX_NAME}/' \
        | sed 's/IMAGE=IMAGE/IMAGE=${TOOLBOX_IMAGE}/' \
        | sed 's/host IMAGE/host ${TOOLBOX_IMAGE}/')"
    if ! eval "${pod}" ; then
        errecho "$0: failed to create container from runlabel '${TOOLBOX_NAME}'"
        exit 1
    fi
}

container_exec() {
    if [[ "$#" -eq 0 ]]; then
        sudo podman attach "${TOOLBOX_NAME}"
    else
        echo "${@}; exit" | sudo podman attach "${TOOLBOX_NAME}"
    fi
}

show_help() {
    errecho "USAGE: toolbox [-h/--help] [command]
toolbox is a small script that launches a container to let you bring in your favorite debugging or admin tools.
The toolbox container is a pet container and will be restarted on following runs.
To remove the container and start fresh, do sudo podman rm ${TOOLBOX_NAME}.

Options:
  -h/--help: Shows this help message

You may override the following variables by setting them in ${TOOLBOXRC}:
- REGISTRY: The registry to pull from. Default: ${REGISTRY}
- IMAGE: The image and tag from the registry to pull. Default: ${IMAGE}
- TOOLBOX_NAME: The name to use for the local container. Default: ${TOOLBOX_NAME}
- AUTHFILE: The location where your registry credentials are stored. Default: ${AUTHFILE}

Example toolboxrc:
REGISTRY=my.special.registry.example.com
IMAGE=debug:latest
TOOLBOX_NAME=special-debug-container
AUTHFILE=/home/core/.docker/config.json"
}

main() {
    # Execute setup first so we get proper variables
    setup
    # If we are passed a help switch, show help and exit
    if [[ "$1" =~ ^(--help|-h)$ ]]; then
        show_help
        exit 0
    fi
    run "$@"
    cleanup
}

main "$@"
