podman/hack/podman-registry
Valentin Rothberg 334d3b1ef3 CI: force registry:2.6
For using the `registry:2.6` image. 2.7 and beyond dropped the
`htpasswd` binary from the rootfs which parts of our CI depends
on.

While this is not a sustainable solution (assuming `htpasswd` is gone
for ever), it unblocks the CI for now.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-06-19 12:58:02 +02:00

250 lines
7.6 KiB
Bash
Executable file

#! /bin/bash
#
# podman-registry - start/stop/monitor a local instance of registry:2
#
ME=$(basename $0)
###############################################################################
# BEGIN defaults
PODMAN_REGISTRY_IMAGE=docker.io/library/registry:2.6
PODMAN_REGISTRY_USER=
PODMAN_REGISTRY_PASS=
PODMAN_REGISTRY_PORT=
# Podman binary to run
PODMAN=${PODMAN:-$(dirname $0)/../bin/podman}
# END defaults
###############################################################################
# BEGIN help messages
missing=" argument is missing; see $ME --help for details"
usage="Usage: $ME [options] [start|stop|ps|logs]
$ME manages a local instance of a container registry.
When called to start a registry, $ME will pull an image
into a local temporary directory, create an htpasswd, start the
registry, and dump a series of environment variables to stdout:
\$ $ME start
PODMAN_REGISTRY_IMAGE=\"docker.io/library/registry:2.6\"
PODMAN_REGISTRY_PORT=\"5050\"
PODMAN_REGISTRY_USER=\"userZ3RZ\"
PODMAN_REGISTRY_PASS=\"T8JVJzKrcl4p6uT\"
Expected usage, therefore, is something like this in a script
eval \$($ME start)
To stop the registry, you will need to know the port number:
$ME -P \$PODMAN_REGISTRY_PORT stop
Override the default image, port, user, password with:
-i IMAGE registry image to pull (default: $PODMAN_REGISTRY_IMAGE)
-u USER registry user (default: random)
-p PASS password for registry user (default: random)
-P PORT port to bind to (on 127.0.0.1) (default: random, 5000-5999)
Other options:
-h display usage message
"
die () {
echo "$ME: $*" >&2
exit 1
}
# END help messages
###############################################################################
# BEGIN option processing
while getopts "i:u:p:P:hv" opt; do
case "$opt" in
i) PODMAN_REGISTRY_IMAGE=$OPTARG ;;
u) PODMAN_REGISTRY_USER=$OPTARG ;;
p) PODMAN_REGISTRY_PASS=$OPTARG ;;
P) PODMAN_REGISTRY_PORT=$OPTARG ;;
h) echo "$usage"; exit 0;;
v) verbose=1 ;;
\?) echo "Run '$ME -h' for help" >&2; exit 1;;
esac
done
shift $((OPTIND-1))
# END option processing
###############################################################################
# BEGIN helper functions
function random_string() {
local length=${1:-10}
head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
}
function podman() {
if [ -z "${PODMAN_REGISTRY_PORT}" ]; then
die "podman port undefined; please invoke me with -P PORT"
fi
if [ -z "${PODMAN_REGISTRY_WORKDIR}" ]; then
PODMAN_REGISTRY_WORKDIR=${TMPDIR:-/tmp}/podman-registry-${PODMAN_REGISTRY_PORT}
if [ ! -d ${PODMAN_REGISTRY_WORKDIR} ]; then
die "$ME: directory does not exist: ${PODMAN_REGISTRY_WORKDIR}"
fi
fi
${PODMAN} --root ${PODMAN_REGISTRY_WORKDIR}/root \
--runroot ${PODMAN_REGISTRY_WORKDIR}/runroot \
"$@"
}
###############
# must_pass # Run a command quietly; abort with error on failure
###############
function must_pass() {
local log=${PODMAN_REGISTRY_WORKDIR}/log
"$@" &> $log
if [ $? -ne 0 ]; then
echo "$ME: Command failed: $*" >&2
cat $log >&2
# If we ever get here, it's a given that the registry is not running.
# Clean up after ourselves.
rm -rf ${PODMAN_REGISTRY_WORKDIR}
exit 1
fi
}
# END helper functions
###############################################################################
# BEGIN action processing
function do_start() {
# If called without a port, assign a random one in the 5xxx range
if [ -z "${PODMAN_REGISTRY_PORT}" ]; then
for port in $(shuf -i 5000-5999);do
if ! { exec 3<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then
PODMAN_REGISTRY_PORT=$port
break
fi
done
fi
PODMAN_REGISTRY_WORKDIR=${TMPDIR:-/tmp}/podman-registry-${PODMAN_REGISTRY_PORT}
if [ -d ${PODMAN_REGISTRY_WORKDIR} ]; then
die "$ME: directory exists: ${PODMAN_REGISTRY_WORKDIR} (another registry might already be running on this port)"
fi
# Randomly-generated username and password, if none given on command line
if [ -z "${PODMAN_REGISTRY_USER}" ]; then
PODMAN_REGISTRY_USER="user$(random_string 4)"
fi
if [ -z "${PODMAN_REGISTRY_PASS}" ]; then
PODMAN_REGISTRY_PASS=$(random_string 15)
fi
# For the next few commands, die on any error
set -e
mkdir -p ${PODMAN_REGISTRY_WORKDIR}
local AUTHDIR=${PODMAN_REGISTRY_WORKDIR}/auth
mkdir -p $AUTHDIR
# Pull registry image, but into a separate container storage
mkdir -p ${PODMAN_REGISTRY_WORKDIR}/root
mkdir -p ${PODMAN_REGISTRY_WORKDIR}/runroot
set +e
# Give it three tries, to compensate for flakes
podman pull ${PODMAN_REGISTRY_IMAGE} &>/dev/null ||
podman pull ${PODMAN_REGISTRY_IMAGE} &>/dev/null ||
must_pass podman pull ${PODMAN_REGISTRY_IMAGE}
# Registry image needs a cert. Self-signed is good enough.
local CERT=$AUTHDIR/domain.crt
must_pass openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout ${AUTHDIR}/domain.key -x509 -days 2 \
-out ${AUTHDIR}/domain.crt \
-subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost"
# Store credentials where container will see them. We can't run
# this one via must_pass because we need its stdout.
podman run --rm \
--entrypoint htpasswd ${PODMAN_REGISTRY_IMAGE} \
-Bbn ${PODMAN_REGISTRY_USER} ${PODMAN_REGISTRY_PASS} \
> $AUTHDIR/htpasswd
if [ $? -ne 0 ]; then
rm -rf ${PODMAN_REGISTRY_WORKDIR}
die "Command failed: podman run [htpasswd]"
fi
# In case someone needs to debug
echo "${PODMAN_REGISTRY_USER}:${PODMAN_REGISTRY_PASS}" \
> $AUTHDIR/htpasswd-plaintext
# Run the registry container.
must_pass podman run --quiet -d \
-p ${PODMAN_REGISTRY_PORT}:5000 \
--name registry \
-v $AUTHDIR:/auth:Z \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
-e "REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt" \
-e "REGISTRY_HTTP_TLS_KEY=/auth/domain.key" \
registry:2.6
# Dump settings. Our caller will use these to access the registry.
for v in IMAGE PORT USER PASS; do
echo "PODMAN_REGISTRY_${v}=\"$(eval echo \$PODMAN_REGISTRY_${v})\""
done
}
function do_stop() {
podman stop registry
podman rm -f registry
rm -rf ${PODMAN_REGISTRY_WORKDIR}
}
function do_ps() {
podman ps -a
}
function do_logs() {
podman logs registry
}
# END action processing
###############################################################################
# BEGIN command-line processing
# First command-line arg must be an action
action=${1?ACTION$missing}
shift
case "$action" in
start) do_start ;;
stop) do_stop ;;
ps) do_ps ;;
logs) do_logs ;;
*) die "Unknown action '$action'; must be start / stop / ps / logs" ;;
esac
# END command-line processing
###############################################################################
exit 0