aboutsummaryrefslogtreecommitdiff
path: root/hack/podman-registry
diff options
context:
space:
mode:
authorEd Santiago <santiago@redhat.com>2020-05-18 12:54:40 -0600
committerValentin Rothberg <rothberg@redhat.com>2020-05-20 10:22:16 +0200
commit973d6244189133b14c8cb77c6b377fb2b2a1501f (patch)
tree2570590e3be2bf68d9f9080ce75a2f62ae658734 /hack/podman-registry
parent4eee0d840f0af81560d89864ea64b95c9e70b18d (diff)
downloadpodman-973d6244189133b14c8cb77c6b377fb2b2a1501f.tar.gz
podman-973d6244189133b14c8cb77c6b377fb2b2a1501f.tar.bz2
podman-973d6244189133b14c8cb77c6b377fb2b2a1501f.zip
New tool: hack/podman-registry, manages local registry
In response to #6207: this is a helper script intended for use in starting and stopping a local container registry. It takes care of port, username, password assignments; generates a self-signed certificate; and starts the container in an isolated podman root/runroot to avoid conflicting with the caller's environment. Intended usage: invoke from shell script, using 'eval' to get results into calling process environment. See help message (-h) for invocation details. This will work for shell scripts but will be difficult if called from Go or C - if that is likely to happen, I'd love to hear suggestions for alternate ways to get the settings back to the caller. Signed-off-by: Ed Santiago <santiago@redhat.com>
Diffstat (limited to 'hack/podman-registry')
-rwxr-xr-xhack/podman-registry231
1 files changed, 231 insertions, 0 deletions
diff --git a/hack/podman-registry b/hack/podman-registry
new file mode 100755
index 000000000..e7708ce6a
--- /dev/null
+++ b/hack/podman-registry
@@ -0,0 +1,231 @@
+#! /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
+
+PODMAN_REGISTRY_USER=
+PODMAN_REGISTRY_PASS=
+PODMAN_REGISTRY_PORT=
+
+# Podman binary to run
+PODMAN=${PODMAN:-$(type -p 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\"
+ 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 \
+ "$@"
+}
+
+# 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
+
+ # Die on any error
+ set -e
+
+ mkdir -p ${PODMAN_REGISTRY_WORKDIR}
+
+ local AUTHDIR=${PODMAN_REGISTRY_WORKDIR}/auth
+ mkdir -p $AUTHDIR
+
+ # We have to be silent; our only output must be env. vars. Log output here.
+ local log=${PODMAN_REGISTRY_WORKDIR}/log
+ touch $log
+
+ # Pull registry image, but into a separate container storage
+ mkdir -p ${PODMAN_REGISTRY_WORKDIR}/root
+ mkdir -p ${PODMAN_REGISTRY_WORKDIR}/runroot
+
+ # Give it three tries, to compensate for flakes
+ podman pull ${PODMAN_REGISTRY_IMAGE} &>> $log ||
+ podman pull ${PODMAN_REGISTRY_IMAGE} &>> $log ||
+ podman pull ${PODMAN_REGISTRY_IMAGE} &>> $log
+
+ # Registry image needs a cert. Self-signed is good enough.
+ local CERT=$AUTHDIR/domain.crt
+ # FIXME: if this fails, we fail silently! It'd be more helpful
+ # to say 'openssl failed' and cat the logfile
+ 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" \
+ &>> $log
+
+ # Store credentials where container will see them
+ podman run --rm \
+ --entrypoint htpasswd ${PODMAN_REGISTRY_IMAGE} \
+ -Bbn ${PODMAN_REGISTRY_USER} ${PODMAN_REGISTRY_PASS} \
+ > $AUTHDIR/htpasswd
+
+ # In case someone needs to debug
+ echo "${PODMAN_REGISTRY_USER}:${PODMAN_REGISTRY_PASS}" \
+ > $AUTHDIR/htpasswd-plaintext
+
+ # Run the registry container.
+ 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 &>> $log
+
+ # 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