| #!/bin/bash |
| set -eo pipefail |
| |
| trap cleanup EXIT |
| |
| # Defaults |
| REGISTRY=registry.redhat.io |
| IMAGE=rhel8/support-tools |
| TOOLBOX_NAME=toolbox-"$(whoami)" |
| TOOLBOXRC="${HOME}"/.toolboxrc |
| |
| 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 |
| elif ! image_fresh; then |
| 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 |
| else |
| echo "Skipping retrieval of new image.." |
| fi |
| fi |
| |
| local runlabel=$(image_runlabel) |
| if ! container_exists; then |
| echo "Spawning a container '$TOOLBOX_NAME' with image '$TOOLBOX_IMAGE'" |
| if [[ -z "$runlabel" ]] || [[ "$runlabel" == "<no value>" ]]; then |
| container_run |
| return |
| else |
| echo "Detected RUN label in the container image. Using that as the default..." |
| container_runlabel |
| return |
| fi |
| else |
| echo "Container '$TOOLBOX_NAME' already exists. Trying to start..." |
| echo "(To remove the container and start with a fresh toolbox, run: sudo 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 |
| |
| 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 |
| } |
| |
| # 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() { |
| local_date=$(sudo podman inspect "$TOOLBOX_IMAGE" --format '{{.Created}}') |
| if ! remote_date=$(sudo skopeo inspect --authfile /var/lib/kubelet/config.json docker://"$TOOLBOX_IMAGE" --format '{{.Created}}'); then |
| echo "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 /var/lib/kubelet/config.json "$TOOLBOX_IMAGE"; then |
| 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 "${REGISTRY}" |
| sudo --preserve-env podman pull "$TOOLBOX_IMAGE" |
| else |
| echo "Exiting..." |
| exit 1 |
| fi |
| fi |
| } |
| |
| container_run() { |
| if ! sudo podman run \ |
| --hostname toolbox \ |
| --name "$TOOLBOX_NAME" \ |
| --privileged \ |
| --net=host \ |
| --pid=host \ |
| --ipc=host \ |
| --tty \ |
| --interactive \ |
| -e HOST=/host \ |
| -e NAME="$TOOLBOX_NAME" \ |
| -e 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" 2>&1; then |
| echo "$0: failed to run 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() { |
| local cmd=$@ |
| if [ ! -n "$cmd" ]; then |
| cmd=$(sudo podman inspect "$TOOLBOX_IMAGE" | jq -re ".[].Config.Cmd[0]") || cmd="/bin/sh" |
| fi |
| |
| sudo podman exec \ |
| --env LANG="$LANG" \ |
| --env TERM="$TERM" \ |
| --tty \ |
| --interactive \ |
| "$TOOLBOX_NAME" \ |
| "$cmd" |
| } |
| |
| show_help() { |
| echo "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 |
| |
| Example toolboxrc: |
| REGISTRY=my.special.registry.example.com |
| IMAGE=debug:latest |
| TOOLBOX_NAME=special-debug-container" |
| } |
| |
| 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 "$@" |