github.com/verrazzano/verrazzano@v1.7.1/tools/scripts/vz-registry-image-helper.sh (about) 1 #!/bin/bash 2 # Copyright (c) 2021, 2022, Oracle and/or its affiliates. 3 # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 4 # 5 # Script to allow users to load Verrazzano images into a private Docker registry. 6 # - Using the Verrazzano BOM, pull/tag/push images into a target registry/repository 7 # - Using a local cache of Verrazzano image tarballs, load into the local Docker registry and push to the remote registry/repo 8 # - Clean up the local registry 9 # 10 set -o pipefail 11 set -o errtrace 12 13 SCRIPT_DIR=$(cd $(dirname "$0"); pwd -P) 14 . ${SCRIPT_DIR}/bom_utils.sh 15 16 # variables 17 TO_REGISTRY= 18 TO_REPO= 19 USELOCAL=0 20 IMAGES_DIR=./images 21 INCREMENTAL_CLEAN=false 22 CLEAN_ALL=false 23 DRY_RUN=false 24 INCLUDE_COMPONENTS= 25 EXCLUDE_COMPONENTS= 26 LIST_IMAGES_ONLY= 27 28 function usage() { 29 ec=${1:-0} 30 echo """ 31 This script is to help pushing Verrazzano container images into a private repository from their default locations, 32 or to generate a tarball of Verrazzano container images. 33 34 usage: 35 36 $0 -t <docker-registry> [-l <archive-path> -r <repository-path>] 37 $0 -t <docker-registry> [-b <path> -r <repository-path>] 38 $0 -f <tarfile-location> [ -l <images-location> ] 39 $0 -c [-b <path> | -l <archive-path>] 40 41 Options: 42 -t <docker-registry> Target docker registry to push to, e.g., iad.ocir.io 43 -r <repository-path> Repository name/prefix for each image, e.g \"path/to/my/image\"; if not specified the default will be used according to the BOM 44 -b <path> Bill of materials (BOM) of Verrazzano components; if not specified, defaults to ./verrazzano-bom.json 45 -l <archive-dir> Use the specified imagesDir to load local Docker image tarballs from instead of pulling from 46 -i <component> Include the specified component in the operation (can be repeated for multiple components) 47 -f <tarfile_dir> The name of the directory that will be used to save Docker image tarballs locally 48 -e <component> Exclude the specified component from the operation (can be repeated for multiple components) 49 -c Clean all local images/tags 50 -z Incrementally clean each local image after it has been successfully pushed 51 -d Dry-run only, do not perform Docker operations 52 -o List components 53 -m <outputfile> List images to output file, do not process them 54 55 Examples: 56 57 # Loads all images into registry 'myreg.io' using the default repository paths for each image in the BOM 58 $0 -t myreg.io 59 60 # Loads all Verrazzano images into registry 'myreg.io' in repository 'myrepo/user1' 61 $0 -t myreg.io -r 'myrepo/user1' 62 63 # Loads all Verrazzano images into registry 'myreg.io' in repository 'myrepo/user1' using the BOM /path/to/my-bom.json 64 # and removes the locally downloaded image after a successful push 65 $0 -c -t myreg.io -r 'myrepo/user1' -b /path/to/my-bom.json 66 67 # Loads all Docker tarball images in the imagesDir /path/to/exploded/tarball into registry 'myreg.io' in repository 'myrepo' 68 $0 -t myreg.io -l /path/to/exploded/tarball -r myrepo 69 70 # Do a dry-run with the tarball location /path/to/exploded/tarball with registry 'myreg.io' in repository 'myrepo' 71 $0 -d -t myreg.io -l /path/to/exploded/tarball -r myrepo 72 73 # List out the Verrazzano components in the default BOM file 74 $0 -d -t myreg.io -o 75 76 # List out the Verrazzano components in the specified BOM file 77 $0 -d -t myreg.io -o -b /path/to/my-bom.json 78 79 # Processes all Verrazzano images *except* verrazzano-platform-operator and verrazzano-application-operator 80 $0 -t myreg.io -r 'myrepo/user1' -b /path/to/my-bom.json -e verrazzano-platform-operator -e verrazzano-application-operator 81 82 # Processes *only* the images for the Verrazzano components cert-manager and istio 83 $0 -t myreg.io -r 'myrepo/user1' -b /path/to/my-bom.json -i cert-manager -i istio 84 85 # Pull and save Verrazzano images locally as tarfiles to the specified location 86 $0 -f /tmp/myvzimages -b /path/to/my-bom.json 87 """ 88 exit ${ec} 89 } 90 91 function exit_trap() { 92 local rc=$? 93 local lc="$BASH_COMMAND" 94 95 if [[ $rc -ne 0 ]]; then 96 echo "Command [$lc] exited with code [$rc]" 97 fi 98 } 99 100 trap exit_trap EXIT 101 102 function run_docker() { 103 local fatal=false 104 if [ "${DRY_RUN}" != "true" ]; then 105 tmpfile=$(mktemp -t vz-helper-docker-err.XXXXXX) 106 docker $* 2>${tmpfile} 107 local result=$? 108 local denied=$(egrep -i "(Anonymous|permission_denied|403.*forbidden)" ${tmpfile}) 109 if [ -n "$denied" ]; then 110 echo """ 111 112 Permission error from Docker: 113 114 $(cat ${tmpfile}) 115 116 Please log into the target registry and try again. 117 118 """ 119 fatal=true 120 elif [ "${result}" != "0" ]; then 121 echo "An error occurred running docker command:" 122 cat ${tmpfile} 123 fi 124 fi 125 rm ${tmpfile} 126 if [ "${fatal}" == "true" ]; then 127 # Fatal error occurred, exit immeditately 128 exit 1 129 fi 130 return ${result} 131 } 132 133 # Wrapper for Docker pull 134 function load() { 135 local archive=$1 136 echo ">> Loading archive: ${archive}" 137 run_docker load -i "${archive}" 138 } 139 140 # Wrapper for Docker pull 141 function pull() { 142 local image=$1 143 echo ">> Pulling image: ${image}" 144 run_docker pull "${image}" 145 } 146 147 # Wrapper for Docker tag 148 function tag() { 149 local from_image=$1 150 local to_image=$2 151 echo ">> Tagging image: ${from_image} to ${to_image}" 152 run_docker tag "${from_image}" "${to_image}" 153 } 154 155 # Wrapper for Docker push 156 function push() { 157 local image=$1 158 echo ">> Pushing image: ${image}" 159 run_docker push "${image}" 160 } 161 162 # Wrapper for Docker save 163 function save() { 164 local tarFile=$1 165 local image=$2 166 echo ">> Saving image: ${image} to ${tarFile}" 167 run_docker save -o "${tarFile}" "${image}" 168 } 169 170 # Wrapper for Docker rmi 171 function remove() { 172 local images=$* 173 echo ">> Removing images: $*" 174 run_docker rmi ${images} 175 } 176 177 # Perform requirements checks and validate arguments 178 function check() { 179 if [ "${INCREMENTAL_CLEAN}" == "true" ] && [ "${CLEAN_ALL}" == "true" ]; then 180 echo "Incremental clean and clean-all both specified, these can not be used together" 181 usage 1 182 fi 183 184 if [ "$USELOCAL" -ne 0 ]; then 185 echo "Use local images specified, ignoring -b if set" 186 if [ -z "${IMAGES-DIR}" ]; then 187 echo "Use local images specified, but no location specified" 188 usage 1 189 fi 190 fi 191 192 if [ -z "${TO_REGISTRY}" ] && [ -z "${TARDIR}" ]; then 193 echo "Target registry not specified!" 194 usage 1 195 fi 196 197 echo "Checking if docker is installed ..." 198 if ! docker --help >/dev/null; then 199 echo "[ERROR] docker is not installed, please install docker" 200 usage 1 201 fi 202 203 echo "Checking if jq is installed ..." 204 if ! jq --help >/dev/null; then 205 echo "[ERROR] jq is not install ... please install jq" 206 usage 1 207 fi 208 209 } 210 211 # Process an image 212 # - Do pull (if necessary) and tag, and then push to the new registry 213 # - attempts up to 10 times before failing 214 # - Cleans up the locally downloaded/loaded image when done 215 function process_image() { 216 local from_image=$1 217 local to_image=$2 218 219 if [ "${CLEAN_ALL}" == "true" ]; then 220 remove ${to_image} ${from_image} 221 return 0 222 fi 223 224 echo "Processing image ${from_image} to ${to_image}" 225 local success=false 226 for i in {1..10}; do 227 # Only pull the image if we are not looking at local images 228 if [ "$USELOCAL" -eq 0 ]; then 229 pull "${from_image}" 230 if [[ $? -ne 0 ]]; then 231 sleep 30 232 continue 233 fi 234 fi 235 236 tag ${from_image} ${to_image} 237 if [[ $? -ne 0 ]]; then 238 sleep 30 239 continue 240 fi 241 242 # push 243 push ${to_image} 244 if [[ $? -ne 0 ]]; then 245 sleep 30 246 continue 247 fi 248 249 success=true 250 break 251 done 252 253 if [ "${INCREMENTAL_CLEAN}" == "true" ]; then 254 remove ${to_image} ${from_image} 255 fi 256 257 if [[ "${success}" == "false" ]]; then 258 echo "[ERROR] Failed to manage image [${from_image}]" 259 exit 1 260 fi 261 } 262 263 # Get the target repo if overridden, otherwise return the provided default 264 function get_target_repo() { 265 local default_repo=$1 266 local target_repo=${TO_REPO} 267 if [ -z "${target_repo}" ]; then 268 target_repo=${default_repo} 269 fi 270 echo "${target_repo}" 271 } 272 273 # Main driver for processing images from a locally downloaded set of tarballs 274 function process_local_archives() { 275 # Loop through tar files 276 echo "Using local image downloads" 277 for file in ${IMAGES_DIR}/*.tar; do 278 if [ ! -e ${file} ]; then 279 echo "Image tar file ${file} does not exist!" 280 exit 1 281 fi 282 # load tar file into the local Docker registry 283 load $file 284 285 # Build up the image name and target image names, and do a tag/push 286 local from_image=$(tar xOvf $file manifest.json | jq -r '.[0].RepoTags[0]') 287 local from_image_name=$(basename $from_image) 288 local from_repository=$(dirname $from_image | cut -d \/ -f 2-) 289 290 local target_repo=$(get_target_repo ${from_repository}) 291 local to_image=${TO_REGISTRY}/${target_repo}/${from_repository}/${from_image_name} 292 if [ ! -z "$LIST_IMAGES_ONLY" ]; then 293 echo ${to_image} >> $LIST_IMAGES_ONLY 294 else 295 process_image ${from_image} ${to_image} 296 fi 297 done 298 } 299 300 # Returns 0 if the specified component is in the excludes list, 1 otherwise 301 function is_component_excluded() { 302 local seeking=$1 303 local excludes=(${EXCLUDE_COMPONENTS}) 304 local in=1 305 for comp in "${excludes[@]}"; do 306 if [[ "$comp" == "$seeking" ]]; then 307 in=0 308 break 309 fi 310 done 311 return $in 312 } 313 314 # Main driver for pulling/tagging/pushing images based on the Verrazzano bill of materials (BOM) 315 function process_images_from_bom() { 316 # Loop through registry components 317 echo "Using image registry ${BOM_FILE}" 318 319 local components=(${INCLUDE_COMPONENTS}) 320 if [ "${#components[@]}" == "0" ]; then 321 components=($(list_components)) 322 fi 323 324 echo "Components: ${components[*]}" 325 326 for component in "${components[@]}"; do 327 if is_component_excluded ${component} ; then 328 echo "Component ${component} excluded" 329 continue 330 fi 331 local subcomponents=($(list_subcomponent_names ${component})) 332 for subcomp in "${subcomponents[@]}"; do 333 echo "Processing images for Verrazzano subcomponent ${component}/${subcomp}" 334 # Load the repository and base image names for the component 335 #local from_repository=$(get_subcomponent_repo $component $subcomp) 336 local image_names=$(list_subcomponent_images $component $subcomp) 337 338 # for each image in the subcomponent list: 339 # - resolve the BOM registry location for the image 340 # - resolve the BOM repository for the image 341 # - build the from/to locations for the image 342 # - call process_image to pull/tag/push the image 343 for base_image in ${image_names}; do 344 local from_registry=$(resolve_image_registry_from_bom $component $subcomp $base_image) 345 local from_image_prefix=${from_registry} 346 local from_repository=$(resolve_image_repo_from_bom $component $subcomp $base_image) 347 if [ -n "${from_repository}" ] && [ "${from_repository}" != "null" ]; then 348 from_image_prefix=${from_image_prefix}/${from_repository} 349 fi 350 351 local to_image_prefix=${TO_REGISTRY} 352 if [ -n "${TO_REPO}" ]; then 353 to_image_prefix=${to_image_prefix}/${TO_REPO} 354 fi 355 to_image_prefix=${to_image_prefix}/${from_repository} 356 357 # Build up the image name and target image name, and do a pull/tag/push 358 local from_image=${from_image_prefix}/${base_image} 359 local to_image=${to_image_prefix}/${base_image} 360 if [ ! -z "$LIST_IMAGES_ONLY" ]; then 361 echo ${to_image} >> $LIST_IMAGES_ONLY 362 else 363 process_image ${from_image} ${to_image} 364 fi 365 done 366 done 367 done 368 } 369 370 # Main driver for pulling/saving images based on the Verrazzano bill of materials (BOM) 371 function pull_and_save_images() { 372 imagesDir=$1 373 374 echo "Creating Verrazzano images tar file ${tarfile}, using ${imagesDir} to store images locally" 375 376 if [ ! -e ${imagesDir} ]; then 377 echo "Creating image imagesDir ${imagesDir}" 378 mkdir -p ${imagesDir} 379 fi 380 381 # Loop through registry components 382 echo "Using image registry ${BOM_FILE}" 383 local components=($(list_components)) 384 for component in "${components[@]}"; do 385 local subcomponent_names=$(list_subcomponent_names ${component}) 386 for subcomponent in ${subcomponent_names}; do 387 local image_names=$(list_subcomponent_images ${component} ${subcomponent}) 388 for base_image in ${image_names}; do 389 local from_registry=$(resolve_image_registry_from_bom ${component} ${subcomponent} $base_image) 390 local from_image_prefix=${from_registry} 391 local from_repository=$(resolve_image_repo_from_bom ${component} ${subcomponent} $base_image) 392 if [ -n "${from_repository}" ] && [ "${from_repository}" != "null" ]; then 393 from_image_prefix=${from_image_prefix}/${from_repository} 394 fi 395 396 local from_image=${from_image_prefix}/${base_image} 397 echo "Processing: ${from_image}" 398 local tarname=$(echo "${from_image}.tar" | sed -e 's;/;_;g' -e 's/:/-/g') 399 local tarLocation=${imagesDir}/${tarname} 400 401 if [ -e ${tarLocation} ]; then 402 # Some images may be replicated in the BOM in different subcomponents, skip the pull/save if we've already 403 # done it for this image 404 echo "${tarLocation} already exists, skipping..." 405 continue 406 fi 407 408 # Pull and save the image 409 pull $from_image 410 save ${tarLocation} ${from_image} 411 412 if [ "${INCREMENTAL_CLEAN}" == "true" ]; then 413 remove ${from_image} 414 fi 415 done 416 done 417 done 418 } 419 420 output_bom_components() { 421 echo """ 422 Verrazzano components in BOM file ${BOM_FILE}: 423 424 $(list_components) 425 """ 426 } 427 428 # Main fn 429 function main() { 430 if [ -n "${TARDIR}" ]; then 431 pull_and_save_images ${TARDIR} 432 elif [ "$USELOCAL" != "0" ]; then 433 process_local_archives 434 else 435 process_images_from_bom 436 fi 437 if [ "${CLEAN_ALL}" == "true" ]; then 438 echo "[SUCCESS] All local images cleaned" 439 else 440 if [ ! -z "$LIST_IMAGES_ONLY" ]; then 441 echo "[SUCCESS] All images listed" 442 else 443 echo "[SUCCESS] All images processed" 444 fi 445 fi 446 } 447 448 while getopts 'hzcdom:b:t:f:r:l:i:e:' opt; do 449 case $opt in 450 b) 451 BOM_FILE=$OPTARG 452 ;; 453 d) 454 DRY_RUN=true 455 ;; 456 e) 457 echo "Exclude component: ${OPTARG}" 458 EXCLUDE_COMPONENTS="${EXCLUDE_COMPONENTS} ${OPTARG}" 459 ;; 460 f) 461 TARDIR=$OPTARG 462 ;; 463 i) 464 echo "Include component: ${OPTARG}" 465 INCLUDE_COMPONENTS="${INCLUDE_COMPONENTS} ${OPTARG}" 466 ;; 467 r) 468 TO_REPO=$OPTARG 469 ;; 470 t) 471 TO_REGISTRY=$OPTARG 472 ;; 473 z) 474 INCREMENTAL_CLEAN=true 475 ;; 476 c) 477 CLEAN_ALL=true 478 ;; 479 o) 480 output_bom_components 481 exit 0 482 ;; 483 m) 484 LIST_IMAGES_ONLY="${OPTARG}" 485 ;; 486 l) 487 USELOCAL=1 488 IMAGES_DIR="${OPTARG}" 489 ;; 490 h | ?) 491 usage 492 ;; 493 esac 494 done 495 496 # Check the system requirements and arguments 497 check 498 # Exec main 499 main