mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00

... primarily so that it can support OCI artifacts. 2.8 already seems to exist in the repo. This requires changing WaitContainerReady to also check stderr (ultimately because docker/distribution was updated to a more recent sirupsen/logrus, which logs by default to stderr instead of stdout). Signed-off-by: Miloslav Trmač <mitr@redhat.com>
271 lines
8.2 KiB
Bash
Executable File
271 lines
8.2 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=quay.io/libpod/registry:2.8
|
|
|
|
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.8\"
|
|
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.
|
|
${PODMAN} unshare rm -rf ${PODMAN_REGISTRY_WORKDIR}
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
###################
|
|
# wait_for_port # Returns once port is available on localhost
|
|
###################
|
|
function wait_for_port() {
|
|
local port=$1 # Numeric port
|
|
|
|
local host=127.0.0.1
|
|
local _timeout=5
|
|
|
|
# Wait
|
|
while [ $_timeout -gt 0 ]; do
|
|
{ exec {unused_fd}<> /dev/tcp/$host/$port; } &>/dev/null && return
|
|
sleep 1
|
|
_timeout=$(( $_timeout - 1 ))
|
|
done
|
|
|
|
die "Timed out waiting for port $port"
|
|
}
|
|
|
|
# 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 {unused_fd}<> /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.
|
|
htpasswd -Bbn ${PODMAN_REGISTRY_USER} ${PODMAN_REGISTRY_PASS} \
|
|
> $AUTHDIR/htpasswd
|
|
if [ $? -ne 0 ]; then
|
|
rm -rf ${PODMAN_REGISTRY_WORKDIR}
|
|
die "Command failed: 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" \
|
|
${PODMAN_REGISTRY_IMAGE}
|
|
|
|
# Confirm that registry started and port is active
|
|
wait_for_port $PODMAN_REGISTRY_PORT
|
|
|
|
# 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
|
|
|
|
# Use straight podman, not our alias function, to avoid 'overlay: EBUSY'
|
|
${PODMAN} unshare 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
|