mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 17:07:20 +08:00 
			
		
		
		
	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>
		
			
				
	
	
		
			250 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			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
 |