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