github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/hack/podman-registry (about) 1 #! /bin/bash 2 # 3 # podman-registry - start/stop/monitor a local instance of registry:2 4 # 5 ME=$(basename $0) 6 7 ############################################################################### 8 # BEGIN defaults 9 10 PODMAN_REGISTRY_IMAGE=quay.io/libpod/registry:2.6 11 12 PODMAN_REGISTRY_USER= 13 PODMAN_REGISTRY_PASS= 14 PODMAN_REGISTRY_PORT= 15 16 # Podman binary to run 17 PODMAN=${PODMAN:-$(dirname $0)/../bin/podman} 18 19 # END defaults 20 ############################################################################### 21 # BEGIN help messages 22 23 missing=" argument is missing; see $ME --help for details" 24 usage="Usage: $ME [options] [start|stop|ps|logs] 25 26 $ME manages a local instance of a container registry. 27 28 When called to start a registry, $ME will pull an image 29 into a local temporary directory, create an htpasswd, start the 30 registry, and dump a series of environment variables to stdout: 31 32 \$ $ME start 33 PODMAN_REGISTRY_IMAGE=\"docker.io/library/registry:2.6\" 34 PODMAN_REGISTRY_PORT=\"5050\" 35 PODMAN_REGISTRY_USER=\"userZ3RZ\" 36 PODMAN_REGISTRY_PASS=\"T8JVJzKrcl4p6uT\" 37 38 Expected usage, therefore, is something like this in a script 39 40 eval \$($ME start) 41 42 To stop the registry, you will need to know the port number: 43 44 $ME -P \$PODMAN_REGISTRY_PORT stop 45 46 Override the default image, port, user, password with: 47 48 -i IMAGE registry image to pull (default: $PODMAN_REGISTRY_IMAGE) 49 -u USER registry user (default: random) 50 -p PASS password for registry user (default: random) 51 -P PORT port to bind to (on 127.0.0.1) (default: random, 5000-5999) 52 53 Other options: 54 55 -h display usage message 56 " 57 58 die () { 59 echo "$ME: $*" >&2 60 exit 1 61 } 62 63 # END help messages 64 ############################################################################### 65 # BEGIN option processing 66 67 while getopts "i:u:p:P:hv" opt; do 68 case "$opt" in 69 i) PODMAN_REGISTRY_IMAGE=$OPTARG ;; 70 u) PODMAN_REGISTRY_USER=$OPTARG ;; 71 p) PODMAN_REGISTRY_PASS=$OPTARG ;; 72 P) PODMAN_REGISTRY_PORT=$OPTARG ;; 73 h) echo "$usage"; exit 0;; 74 v) verbose=1 ;; 75 \?) echo "Run '$ME -h' for help" >&2; exit 1;; 76 esac 77 done 78 shift $((OPTIND-1)) 79 80 # END option processing 81 ############################################################################### 82 # BEGIN helper functions 83 84 function random_string() { 85 local length=${1:-10} 86 87 head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length 88 } 89 90 function podman() { 91 if [ -z "${PODMAN_REGISTRY_PORT}" ]; then 92 die "podman port undefined; please invoke me with -P PORT" 93 fi 94 95 if [ -z "${PODMAN_REGISTRY_WORKDIR}" ]; then 96 PODMAN_REGISTRY_WORKDIR=${TMPDIR:-/tmp}/podman-registry-${PODMAN_REGISTRY_PORT} 97 if [ ! -d ${PODMAN_REGISTRY_WORKDIR} ]; then 98 die "$ME: directory does not exist: ${PODMAN_REGISTRY_WORKDIR}" 99 fi 100 fi 101 102 ${PODMAN} --root ${PODMAN_REGISTRY_WORKDIR}/root \ 103 --runroot ${PODMAN_REGISTRY_WORKDIR}/runroot \ 104 "$@" 105 } 106 107 ############### 108 # must_pass # Run a command quietly; abort with error on failure 109 ############### 110 function must_pass() { 111 local log=${PODMAN_REGISTRY_WORKDIR}/log 112 113 "$@" &> $log 114 if [ $? -ne 0 ]; then 115 echo "$ME: Command failed: $*" >&2 116 cat $log >&2 117 118 # If we ever get here, it's a given that the registry is not running. 119 # Clean up after ourselves. 120 ${PODMAN} unshare rm -rf ${PODMAN_REGISTRY_WORKDIR} 121 exit 1 122 fi 123 } 124 125 # END helper functions 126 ############################################################################### 127 # BEGIN action processing 128 129 function do_start() { 130 # If called without a port, assign a random one in the 5xxx range 131 if [ -z "${PODMAN_REGISTRY_PORT}" ]; then 132 for port in $(shuf -i 5000-5999);do 133 if ! { exec 3<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then 134 PODMAN_REGISTRY_PORT=$port 135 break 136 fi 137 done 138 fi 139 140 PODMAN_REGISTRY_WORKDIR=${TMPDIR:-/tmp}/podman-registry-${PODMAN_REGISTRY_PORT} 141 if [ -d ${PODMAN_REGISTRY_WORKDIR} ]; then 142 die "$ME: directory exists: ${PODMAN_REGISTRY_WORKDIR} (another registry might already be running on this port)" 143 fi 144 145 # Randomly-generated username and password, if none given on command line 146 if [ -z "${PODMAN_REGISTRY_USER}" ]; then 147 PODMAN_REGISTRY_USER="user$(random_string 4)" 148 fi 149 if [ -z "${PODMAN_REGISTRY_PASS}" ]; then 150 PODMAN_REGISTRY_PASS=$(random_string 15) 151 fi 152 153 # For the next few commands, die on any error 154 set -e 155 156 mkdir -p ${PODMAN_REGISTRY_WORKDIR} 157 158 local AUTHDIR=${PODMAN_REGISTRY_WORKDIR}/auth 159 mkdir -p $AUTHDIR 160 161 # Pull registry image, but into a separate container storage 162 mkdir -p ${PODMAN_REGISTRY_WORKDIR}/root 163 mkdir -p ${PODMAN_REGISTRY_WORKDIR}/runroot 164 165 set +e 166 167 # Give it three tries, to compensate for flakes 168 podman pull ${PODMAN_REGISTRY_IMAGE} &>/dev/null || 169 podman pull ${PODMAN_REGISTRY_IMAGE} &>/dev/null || 170 must_pass podman pull ${PODMAN_REGISTRY_IMAGE} 171 172 # Registry image needs a cert. Self-signed is good enough. 173 local CERT=$AUTHDIR/domain.crt 174 must_pass openssl req -newkey rsa:4096 -nodes -sha256 \ 175 -keyout ${AUTHDIR}/domain.key -x509 -days 2 \ 176 -out ${AUTHDIR}/domain.crt \ 177 -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost" 178 179 # Store credentials where container will see them. We can't run 180 # this one via must_pass because we need its stdout. 181 podman run --rm \ 182 --entrypoint htpasswd ${PODMAN_REGISTRY_IMAGE} \ 183 -Bbn ${PODMAN_REGISTRY_USER} ${PODMAN_REGISTRY_PASS} \ 184 > $AUTHDIR/htpasswd 185 if [ $? -ne 0 ]; then 186 rm -rf ${PODMAN_REGISTRY_WORKDIR} 187 die "Command failed: podman run [htpasswd]" 188 fi 189 190 # In case someone needs to debug 191 echo "${PODMAN_REGISTRY_USER}:${PODMAN_REGISTRY_PASS}" \ 192 > $AUTHDIR/htpasswd-plaintext 193 194 # Run the registry container. 195 must_pass podman run --quiet -d \ 196 -p ${PODMAN_REGISTRY_PORT}:5000 \ 197 --name registry \ 198 -v $AUTHDIR:/auth:Z \ 199 -e "REGISTRY_AUTH=htpasswd" \ 200 -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ 201 -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \ 202 -e "REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt" \ 203 -e "REGISTRY_HTTP_TLS_KEY=/auth/domain.key" \ 204 registry:2.6 205 206 # Dump settings. Our caller will use these to access the registry. 207 for v in IMAGE PORT USER PASS; do 208 echo "PODMAN_REGISTRY_${v}=\"$(eval echo \$PODMAN_REGISTRY_${v})\"" 209 done 210 } 211 212 213 function do_stop() { 214 podman stop registry 215 podman rm -f registry 216 217 # Use straight podman, not our alias function, to avoid 'overlay: EBUSY' 218 ${PODMAN} unshare rm -rf ${PODMAN_REGISTRY_WORKDIR} 219 } 220 221 222 function do_ps() { 223 podman ps -a 224 } 225 226 227 function do_logs() { 228 podman logs registry 229 } 230 231 # END action processing 232 ############################################################################### 233 # BEGIN command-line processing 234 235 # First command-line arg must be an action 236 action=${1?ACTION$missing} 237 shift 238 239 case "$action" in 240 start) do_start ;; 241 stop) do_stop ;; 242 ps) do_ps ;; 243 logs) do_logs ;; 244 *) die "Unknown action '$action'; must be start / stop / ps / logs" ;; 245 esac 246 247 # END command-line processing 248 ############################################################################### 249 250 exit 0