#!/bin/bash

#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# script based on https://github.com/coreos/toolbox/

set -eo pipefail

trap cleanup EXIT

# Defaults
REGISTRY=registry.opensuse.org
IMAGE=opensuse/toolbox
TOOLBOX_NAME=toolbox-"${USER}"
TOOLBOXRC="${HOME}"/.toolboxrc
TOOLBOX_SHELL="/bin/bash"
SUDO=

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

run() {
    if ! image_exists; then
        image_pull
    fi

    local runlabel=$(image_runlabel)
    if ! container_exists; then
        echo "Spawning a container '$TOOLBOX_NAME' with image '$TOOLBOX_IMAGE'"
        if [[ -z "$runlabel" ]]; then
            container_create
        else
            echo "Detected RUN label in the container image. Using that as the default..."
            container_runlabel
            return
        fi
	# We want to do the user setup only when the container is created for the first time
	[[ ! -z ${CREATE_AS_USER} ]] && SETUP_USER=true
    else
        echo "Container '$TOOLBOX_NAME' already exists. Trying to start..."
        echo "(To remove the container and start with a fresh toolbox, run: podman rm '$TOOLBOX_NAME')"
    fi

    local state=$(container_state)
    if [[ "$state" == configured ]] || [[ "$state" == exited ]] || [[ "$state" == stopped ]]; then
        container_start
    elif [[ "$state" != running ]]; then
        echo "Container '$TOOLBOX_NAME' in unknown state: '$state'"
        return 1
    fi

    if [[ "${SETUP_USER}" = "true" ]]; then
        echo "Setting up user '${USER_NAME}' (with 'sudo' access) inside the container..."
        echo "(NOTE that, if 'sudo' and related packages are not present in the image already,"
        echo "this may take some time. But this will only happen now that the toolbox is being created)"
        cat <<EOF > /tmp/${TOOLBOX_NAME}-user-setup.sh
#!/bin/bash
groupadd -g ${USER_GID} ${USER_GNAME} &> /dev/null
useradd -M -N -g ${USER_GNAME} -u ${USER_ID} ${USER_NAME} &> /dev/null
zypper install -y --no-recommends sudo system-group-wheel &> /dev/null
echo "%wheel ALL = (root) NOPASSWD:ALL" > /etc/sudoers.d/wheel 2> /dev/null
usermod -G wheel -a ${USER_NAME} &> /dev/null
EOF
        ${SUDO} podman cp /tmp/${TOOLBOX_NAME}-user-setup.sh ${TOOLBOX_NAME}:/tmp/user-setup.sh
        ${SUDO} podman exec --user root ${TOOLBOX_NAME} bash /tmp/user-setup.sh
    fi

    echo "Container started successfully. To exit, type 'exit'."
    container_exec "$@"
}

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

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

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

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

image_runlabel() {
    ${SUDO} podman container runlabel --display RUN "$TOOLBOX_IMAGE" 2> /dev/null
}

image_pull() {
    ${SUDO} podman pull "$TOOLBOX_IMAGE"
}

container_create() {
    if ! ${SUDO} podman create \
                 --hostname toolbox \
                 --name "$TOOLBOX_NAME" \
                 --network host \
                 --privileged \
                 --security-opt label=disable ${CREATE_AS_USER} \
                 --volume /:/media/root:rslave \
		 --volume /dev:/dev:rslave \
                 "$TOOLBOX_IMAGE" sleep +Inf 2>&1; then
        echo "$0: failed to create container '$TOOLBOX_NAME'"
        exit 1
    fi
}

container_start() {
    if ! ${SUDO} podman start "$TOOLBOX_NAME" 2>&1; then
        echo "$0: failed to start container '$TOOLBOX_NAME'"
        exit 1
    fi
}

container_runlabel() {
    if ! ${SUDO} podman container runlabel --name "$TOOLBOX_NAME" RUN "$TOOLBOX_IMAGE" 2>&1; then
        echo "$0: failed to runlabel on image '$TOOLBOX_IMAGE'"
        exit 1
    fi
}

container_exec() {
    ${SUDO} podman exec \
            --env LANG="$LANG" \
            --env TERM="$TERM" \
            --interactive \
            --tty ${EXEC_AS_USER} \
            "$TOOLBOX_NAME" \
            "$@"
}

show_help() {
    echo "USAGE: toolbox [[-h/--help] | [-r/--root] [-u/--user] [-t/--tag <tag>] [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 podman rm ${TOOLBOX_NAME}.

Options:
  -h/--help: Shows this help message
  -u/--user: Run as the current user inside the container
  -r/--root: Runs podman via sudo as root
  -t/--tag <tag>: Add <tag> to the toolbox name

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
- TOOLBOX_SHELL: Standard shell if no other commands are given. Default: $TOOLBOX_SHELL

Example toolboxrc:
REGISTRY=my.special.registry.example.com
IMAGE=debug:latest
TOOLBOX_NAME=special-debug-container
TOOLBOX_SHELL=/bin/bash"
}

main() {
    # Execute setup first so we get proper variables
    setup
    # If we are passed a help switch, show help and exit
    ARGS=`getopt -o hrut: --long help,root,user,tag: -n toolbox -- "$@"`
    eval set -- "$ARGS"
    while true; do
        case "$1" in
            -h|--help)
                show_help
                exit 0
                ;;
            -r|--root)
                shift
                SUDO=sudo
                ;;
            -u|--user)
                shift
                USER_ID=`id -u`; USER_GID=`id -g`
                USER_NAME=`id -un` ; USER_GNAME=`id -gn`
                USER_HOME=$HOME
                TOOLBOX_NAME="${TOOLBOX_NAME}-user"

                # We want to keep the pid namespace of the running user.
                # We, however, use root:root while creating, so that later we
                # can modify the user's name, groups, etc, within the container.
                CREATE_AS_USER="--pid host --userns=keep-id -v ${HOME}:${HOME} --user root:root -w `pwd`"
                EXEC_AS_USER="--user ${USER_ID}:${USER_GID}"
                ;;
            -t|--tag)
                TOOLBOX_NAME="${TOOLBOX_NAME}-$2"
                shift 2
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "unknown parameter: '$1'"
                show_help
                exit 1
                ;;
        esac
    done

    if [ -z "$*" ]; then
	run ${TOOLBOX_SHELL}
    else
	run "$@"
    fi
    cleanup
}

main "$@"
