github.com/verrazzano/verrazzano@v1.7.0/tools/scripts/manage-ocir-repositories.sh (about) 1 #!/bin/bash 2 # Copyright (c) 2021, 2023, 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 # Create a Docker repository in a specific compartment using an exploded tarball of Verrazzano images; useful for 6 # scoping a repo someplace other than the root compartment. 7 # 8 set -o pipefail 9 set -o errtrace 10 11 DRY_RUN= 12 IMAGES_DIR=. 13 REGION="" 14 REGION_SHORT_NAME="" 15 COMPARTMENT_ID="" 16 PARENT_REPO="" 17 USE_BOM=false 18 CREATE_REPOS=false 19 DELETE_REPOS=false 20 DELETE_ALL_REPOS=false 21 USE_LOCAL_IMAGES=false 22 INCLUDE_COMPONENTS= 23 EXCLUDE_COMPONENTS= 24 25 SCRIPT_DIR=$(cd $(dirname "$0"); pwd -P) 26 . ${SCRIPT_DIR}/bom_utils.sh 27 28 usage() { 29 ec=${1:-0} 30 echo """ 31 Utility script for creating or deleting OCIR repos for Verrazzano images. 32 33 You can create OCIR repos in a valid OCI tenancy compartment using a user-provided repository prefix from either 34 35 - a set of exported Docker images tarballs located in a local directory in a specific 36 - a valid Verrazzano BOM registry file 37 38 For the local images case, this script reads the image repo information out of each tar file; in the BOM case it will 39 retrieve the image information from there. 40 41 It then uses the above information to create a corresponding image repo in the target tenancy compartment, under that 42 tenancy's namespace. 43 44 See https://docs.oracle.com/en-us/iaas/Content/Registry/Tasks/registrycreatingarepository.htm for details on 45 repository creation in an OCI tenancy. 46 47 For the deletion case, the script uses the provided compartment ID (-i) and repository prefix (-p) to find all matching 48 repositories in the compartment and deletes them. 49 50 In both cases, you can provide either the full region name (e.g., "us-phoenix-1", or the region short name (e.g., "phx"). 51 52 Create usage: 53 54 $0 -c -p <parent-repo> -i <compartment-ocid> [-r <region-name> | -s <region-code> ] [ -l <path> | -b <path> ] [ -n <component-name> -e <component-name> ] 55 56 Delete usage: 57 58 $0 -d -p <parent-repo> -i <compartment-ocid> [-r <region-name> | -s <region-code> ] 59 60 -a Used with -d, delete all repositories in specified compartment matching -p <repo-path> 61 -b <path> Bill of materials (BOM) of Verrazzano components; if not specified, defaults to ./verrazzano-bom.json 62 -c Create repository 63 -d Delete repository 64 -e Exclude component (when used with -b) 65 -f Used -with -d, force deletion without prompting 66 -i <ocid> Compartment ID 67 -l <path> Used with -c, images directory location for creating repos based on saved local image tar files 68 -n Include component (when used with -b) 69 -p <repo-prefix> Parent repo, without the tenancy/ObjectStore namespace prefix 70 -r <region-name> Region name (e.g., "us-phoenix-1") 71 -s <region-code> Region short name (e.g., "phx", "lhr") 72 -w Used with -d, to wait for delete completion 73 -z Dry-run mode; runs without executing OCI repository commands 74 75 76 77 # Create repos in compartment ocid.compartment.oc1..blah, with the repository prefix "myreporoot/testuser/myrepo/v8o", and the extracted tarball location is /tmp/exploded: 78 $0 -c -p myreporoot/testuser/myrepo/v8o -r uk-london-1 -i ocid.compartment.oc1..blah -d /tmp/exploded 79 80 # Create repos in compartment ocid.compartment.oc1..blah, with the repository prefix myreporoot/testuser/myrepo/v8o using a BOM file 81 $0 -c -p myreporoot/testuser/myrepo/v8o -r uk-london-1 -i ocid.compartment.oc1..blah -b /tmp/local-bom.json 82 83 # Only create repos for Istio and NGINX components 84 $0 -c -p myreporoot/testuser/myrepo/v8o -r uk-london-1 -i ocid.compartment.oc1..blah -b /tmp/local-bom.json -n istio -n ingress-nginx 85 86 # Force-delete all repos starting with myreporoot/testuser/myrepo/v8o in the specified compartment and wait for it to finish 87 $0 -d -a -p myreporoot/testuser/myrepo/v8o -r uk-london-1 -i ocid.compartment.oc1..blah -f -w 88 89 # Create only the cert-manager repos in the specified BOM file and wait for it to finish 90 $0 -c -r phx -i ocid1.compartment.oc1..aaaaaaaa7cfqxbsnon63unlmm5z63zidx5wvq4gieuc5kixemfitzliwvxeq -p myreporoot/testuser/myrepo/v8o -n cert-manager -b ./master-generated-verrazzano-bom.json 91 92 # Force-delete only the cert-manager repos in the specified BOM file and wait for it to finish 93 $0 -d -r phx -i ocid1.compartment.oc1..aaaaaaaa7cfqxbsnon63unlmm5z63zidx5wvq4gieuc5kixemfitzliwvxeq -p myreporoot/testuser/myrepo/v8o -n cert-manager -b ./master-generated-verrazzano-bom.json -f -w 94 """ 95 exit ${ec} 96 } 97 98 function create_ocir_repo() { 99 local repo_path=$1 100 101 local is_public="false" 102 if [[ "$from_image_name" =~ rancher.* ]] || [[ "$from_image_name" == "verrazzano-platform-operator" ]] \ 103 || [[ "$from_image_name" == "fluentd-kubernetes-daemonset" ]] || [[ "$from_image_name" == "proxyv2" ]] \ 104 || [[ "$from_image_name" == "weblogic-monitoring-exporter" ]] || [[ "$from_image_name" =~ cluster-api.* ]]; then 105 # Rancher repos must be public 106 is_public="true" 107 fi 108 109 echo "Creating repository ${repo_path} in ${REGION}, public: ${is_public}" 110 111 if [ "${DRY_RUN}" != "true" ]; then 112 oci --region ${REGION} artifacts container repository create --display-name ${repo_path} \ 113 --is-public ${is_public} --compartment-id ${COMPARTMENT_ID} 114 else 115 echo "Dry run, skipping action..." 116 fi 117 } 118 119 function delete_ocir_repo_by_ocid() { 120 local id=$1 121 repo_name=$(oci --region ${REGION} artifacts container repository get --repository-id ${id} | jq -r '.data."display-name"') 122 echo "Deleting repository ${repo_name}, id: ${id}" 123 if [ "${DRY_RUN}" != "true" ]; then 124 oci --region ${REGION} artifacts container repository delete --repository-id ${id} ${FORCE} ${WAIT_FOR_STATE} 125 else 126 echo "Dry run, skipping action..." 127 fi 128 } 129 130 # Main driver for processing images from a locally downloaded set of tarballs 131 function process_image_repos_from_archives() { 132 # Loop through tar files 133 echo "Using local image downloads" 134 for file in ${IMAGES_DIR}/*.tar; do 135 echo "Processing file ${file}" 136 if [ ! -e ${file} ]; then 137 echo "Image tar file ${file} does not exist!" 138 exit 1 139 fi 140 141 # Build up the image name and target image names, and create the repo 142 local from_image=$(tar xOvf $file manifest.json | jq -r '.[0].RepoTags[0]') 143 local from_image_name=$(basename $from_image | cut -d \: -f 1) 144 local resolvedRepository=$(dirname $from_image | cut -d \/ -f 2-) 145 146 local repo_path=${resolvedRepository}/${from_image_name} 147 if [ -n "${PARENT_REPO}" ]; then 148 repo_path=${PARENT_REPO}/${repo_path} 149 fi 150 151 process_image_repo ${repo_path} 152 done 153 } 154 155 # Returns 0 if the specified component is in the excludes list, 1 otherwise 156 function is_component_excluded() { 157 local seeking=$1 158 local excludes=(${EXCLUDE_COMPONENTS}) 159 local in=1 160 for comp in "${excludes[@]}"; do 161 if [[ "$comp" == "$seeking" ]]; then 162 in=0 163 break 164 fi 165 done 166 return $in 167 } 168 169 function process_image_repo() { 170 local repo_path=$1 171 if [ "${CREATE_REPOS}" == "true" ]; then 172 create_ocir_repo ${repo_path} 173 elif [ "${DELETE_REPOS}" == "true" ]; then 174 delete_all_repos_for_path ${repo_path} 175 fi 176 } 177 178 function process_image_repos_from_bom() { 179 # Loop through registry components 180 echo "Using image registry ${BOM_FILE}" 181 182 local components=(${INCLUDE_COMPONENTS}) 183 if [ "${#components[@]}" == "0" ]; then 184 components=($(list_components)) 185 fi 186 187 echo "Components: ${components[*]}" 188 189 for component in "${components[@]}"; do 190 if is_component_excluded ${component} ; then 191 echo "Component ${component} excluded" 192 continue 193 fi 194 local subcomponents=($(list_subcomponent_names ${component})) 195 for subcomp in "${subcomponents[@]}"; do 196 echo "Processing images for Verrazzano subcomponent ${component}/${subcomp}" 197 # Load the repository and base image names for the component 198 #local resolvedRepository=$(get_subcomponent_repo $component $subcomp) 199 local image_names=$(list_subcomponent_images $component $subcomp) 200 201 # for each image in the subcomponent list: 202 # - resolve the BOM registry location for the image 203 # - resolve the BOM repository for the image 204 # - build the from/to locations for the image 205 # - call process_image to pull/tag/push the image 206 for base_image in ${image_names}; do 207 local resolvedRegistry=$(resolve_image_registry_from_bom $component $subcomp $base_image) 208 local from_image_prefix=${PARENT_REPO} 209 local resolvedRepository=$(resolve_image_repo_from_bom $component $subcomp $base_image) 210 if [ -n "${resolvedRepository}" ] && [ "${resolvedRepository}" != "null" ]; then 211 from_image_prefix=${from_image_prefix}/${resolvedRepository} 212 fi 213 214 # Build up the image name and target image name, and do a pull/tag/push 215 local imageName=$(echo $base_image | cut -d \: -f 1) 216 local repo_path=${from_image_prefix}/${imageName} 217 218 process_image_repo ${repo_path} 219 done 220 done 221 done 222 } 223 224 function delete_all_repos_for_path() { 225 repo_prefix=$1 226 227 if [ -z "${repo_prefix}" ]; then 228 echo "No repository prefix specified for deletion" 229 exit 1 230 fi 231 repo_ids="$(oci --region ${REGION} artifacts container repository list --compartment-id ${COMPARTMENT_ID} | \ 232 jq -r --arg pattern "${repo_prefix}" '.data.items[] | select(."display-name"|test($pattern)) | .id')" 233 234 for id in ${repo_ids}; do 235 delete_ocir_repo_by_ocid $id 236 done 237 238 return 0 239 } 240 241 while getopts "acdfhwzb:e:i:l:n:p:r:s:" opt; do 242 case ${opt} in 243 a) # Delete all repos, with -d 244 DELETE_ALL_REPOS=true 245 ;; 246 b) # Create repo 247 USE_BOM=true 248 BOM_FILE=${OPTARG} 249 ;; 250 c) # Create repo 251 CREATE_REPOS=true 252 ;; 253 d) # Delete repo 254 DELETE_REPOS=true 255 ;; 256 e) 257 echo "Exclude component: ${OPTARG}" 258 EXCLUDE_COMPONENTS="${EXCLUDE_COMPONENTS} ${OPTARG}" 259 ;; 260 f ) # force delete, no prompt 261 FORCE="--force" 262 ;; 263 i) # compartment ID 264 COMPARTMENT_ID=${OPTARG} 265 ;; 266 l) # images dir 267 USE_LOCAL_IMAGES=true 268 IMAGES_DIR="${OPTARG}" 269 ;; 270 n) 271 echo "Include component: ${OPTARG}" 272 INCLUDE_COMPONENTS="${INCLUDE_COMPONENTS} ${OPTARG}" 273 ;; 274 p) # parent repo 275 PARENT_REPO=${OPTARG} 276 ;; 277 r) # region 278 REGION=${OPTARG} 279 ;; 280 s ) 281 REGION_SHORT_NAME="${OPTARG}" 282 ;; 283 w ) # wait for deletion 284 WAIT_FOR_STATE="--wait-for-state DELETED" 285 ;; 286 z) # dry-run 287 DRY_RUN=true 288 ;; 289 h) 290 usage 0 291 ;; 292 *) 293 usage 0 294 ;; 295 esac 296 done 297 shift $((OPTIND - 1)) 298 299 function check() { 300 if [ "${CREATE_REPOS}" == "${DELETE_REPOS}" ]; then 301 echo "Must specify only one valid operation, only one of -c or -d must be set" 302 exit 1 303 fi 304 305 if [[ "${DELETE_REPOS}" == "true" ]]; then 306 if [[ "${USE_LOCAL_IMAGES}" == "true" && (-n "${INCLUDE_COMPONENTS}" || -n "${EXCLUDE_COMPONENTS}") ]]; then 307 echo "Delete repositories, can only use -e or -n with -b (BOM File) option, not -l" 308 exit 1 309 fi 310 fi 311 312 if [ "${CREATE_REPOS}" == "true" ] && [ "${DELETE_ALL_REPOS}" == "true" ]; then 313 echo "Warning: -a (delete all repos) set with -c, ignoring" 314 DELETE_ALL_REPOS=false 315 fi 316 317 if [[ "${DELETE_REPOS}" == "true" && "${USE_LOCAL_IMAGES}" == "true" ]]; then 318 echo "Can not specify -l with -d" 319 exit 1 320 fi 321 322 if [[ "${DELETE_REPOS}" == "true" && "${USE_BOM}" == "false" && "${DELETE_ALL_REPOS}" == "false" ]]; then 323 echo "Delete repostories, must specify exactly one of either -a (all repos) or -b (BOM file)" 324 exit 1 325 fi 326 327 if [[ "${DELETE_ALL_REPOS}" == "true" && (-n "${INCLUDE_COMPONENTS}" || -n "${EXCLUDE_COMPONENTS}" || "${USE_BOM}" == "true" || "${USE_LOCAL_IMAGES}" == "true") ]]; then 328 echo "Can not specify -l, -b, -n, or -e with -a" 329 exit 1 330 fi 331 332 if [ "${USE_LOCAL_IMAGES}" == "true" ] && [ -z "${IMAGES_DIR}" ]; then 333 echo "Use local images specified, but no location specified" 334 exit 1 335 fi 336 337 if [ -z "${PARENT_REPO}" ]; then 338 echo "Repository pattern not provided" 339 exit 1 340 fi 341 342 if [ -z "${COMPARTMENT_ID}" ]; then 343 echo "Compartment ID not provided" 344 exit 1 345 fi 346 347 echo "Checking if OCI CLI is installed ..." 348 if ! oci --help >/dev/null; then 349 echo "[ERROR] OCI CLI is not installed, please install" 350 exit 1 351 fi 352 353 echo "Checking if jq is installed ..." 354 if ! jq --help >/dev/null; then 355 echo "[ERROR] jq is not install ... please install jq" 356 exit 1 357 fi 358 359 if [ -z "${REGION}" ]; then 360 if [ -z "${REGION_SHORT_NAME}" ]; then 361 echo "Must provide either the full or the short region name" 362 exit 1 363 fi 364 echo "REGION_SHORT_NAME=$REGION_SHORT_NAME" 365 REGION=$(oci --region us-phoenix-1 iam region list | jq -r --arg regionAbbr ${REGION_SHORT_NAME} '.data[] | select(.key|test($regionAbbr;"i")) | .name') 366 if [ -z "${REGION}" ] || [ "null" == "${REGION}" ]; then 367 echo "Invalid short region name ${REGION_SHORT_NAME}" 368 exit 1 369 fi 370 fi 371 } 372 373 function main() { 374 if [ "${DELETE_ALL_REPOS}" == "true" ] && [ "${DELETE_REPOS}" == "true" ]; then 375 echo "Deleting all OCIR repositories matching the path ${PARENT_REPO}" 376 delete_all_repos_for_path ${PARENT_REPO} 377 else 378 if [ "${USE_LOCAL_IMAGES}" == "true" ]; then 379 echo "Processing images from local archives at ${IMAGES_DIR}" 380 process_image_repos_from_archives 381 elif [ "${USE_BOM}" == "true" ]; then 382 echo "Processing images from BOM file ${BOM_FILE}" 383 process_image_repos_from_bom 384 fi 385 fi 386 387 echo "Done." 388 } 389 390 check 391 main 392