blob: ac6ce551efe6c6025c21ae3d3251d097fb79aa47 [file] [log] [blame]
#!/bin/bash
set -eo pipefail
trap cleanup EXIT
# Defaults
REGISTRY=registry.redhat.io
IMAGE=rhel8/support-tools
AUTHFILE=/var/lib/kubelet/config.json
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
if container_exists; then
sudo podman rm "${TOOLBOX_NAME}"
fi
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
if container_exists; then
sudo podman rm "${TOOLBOX_NAME}"
fi
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_create
else
echo "Detected RUN label in the container image. Using that as the default..."
container_create_runlabel
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 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() {
echo "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 skopeo inspect --authfile "${AUTHFILE}" 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 "${AUTHFILE}" "$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 --authfile "${AUTHFILE}" "${REGISTRY}"
sudo --preserve-env podman pull --authfile "${AUTHFILE}" "$TOOLBOX_IMAGE"
else
echo "Exiting..."
exit 1
fi
fi
}
container_create() {
if ! sudo podman create \
--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 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_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
echo "$0: failed to create container from runlabel '$TOOLBOX_NAME'"
exit 1
fi
}
container_exec() {
if [[ "$#" -eq 0 ]]; then
cmd=$(sudo podman image inspect "${TOOLBOX_IMAGE}" | jq -re ".[].Config.Cmd[0]") || cmd="/bin/sh"
sudo podman exec \
--env LANG="$LANG" \
--env TERM="$TERM" \
--tty \
--interactive \
"$TOOLBOX_NAME" \
"$cmd"
else
sudo podman exec \
--env LANG="$LANG" \
--env TERM="$TERM" \
--tty \
--interactive \
"$TOOLBOX_NAME" \
"$@"
fi
}
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
- 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 "$@"