#!/bin/bash # find-zone-by-name - SFCC SCAPI helper to find a CDN zone by name substring # # Usage: # find-zone-by-name [options] # find-zone-by-name -h # # Options: # -j, --jwt JWT bearer token (required unless J_JWT is set) # -s, --shortcode SCAPI shortcode (required unless J_SHORTCODE is set) # -r, --realm Realm ID (required unless J_REALM is set) # -i, --instance Instance name (required unless J_INSTANCE is set) # -t, --target Target zone name substring (required unless J_TARGET is set) # -h, --help Show this help message # # Environment: # J_JWT JWT bearer token (e.g. ) # J_SHORTCODE SCAPI shortcode (e.g. ) # J_REALM Realm ID (e.g. ) # J_INSTANCE Instance name (e.g. ) # J_TARGET Zone name substring (e.g. ) _find_zone_by_name() ( local SCRIPT_NAME; SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" case "${BASH_SOURCE[0]}" in /dev/*|/proc/*) SCRIPT_NAME="" ;; esac case "$SCRIPT_NAME" in ""|bash|sh|zsh|dash) SCRIPT_NAME="find-zone-by-name" ;; esac local MAX_RESULTS_PER_REQUEST=50 # Limit determined by the API local COUNT_HEADER_NAME="sfdc-pagination-result-count" local TOTAL_HEADER_NAME="sfdc-pagination-total-count" _error() { echo "[ERR][$SCRIPT_NAME] $*" >&2; } _show_help() { local s; [ -t 1 ] && s=$'\033[4m' local r; [ -t 1 ] && r=$'\033[24m' cat </zones/info until it finds a zone whose name contains the given substring. The matching zone's JSON object is printed to stdout. Prefixed environment variables (J_*) are honored as defaults for flags. OPTIONS -j, --jwt ${s}jwt${r} JWT bearer token (required unless J_JWT set) -s, --shortcode ${s}shortcode${r} SCAPI shortcode (required unless J_SHORTCODE set) -r, --realm ${s}realm${r} Realm ID (required unless J_REALM set) -i, --instance ${s}instance${r} Instance name (required unless J_INSTANCE set) -t, --target ${s}name${r} Target zone name substring (required unless J_TARGET set) -h, --help Show this help message ENVIRONMENT J_JWT JWT bearer token (default for -j/--jwt) J_SHORTCODE SCAPI shortcode (default for -s/--shortcode) J_REALM Realm ID (default for -r/--realm) J_INSTANCE Instance name (default for -i/--instance) J_TARGET Zone name substring (default for -t/--target) DEPENDENCIES curl, jq EXIT STATUS 0 Zone found and printed 1 No matching zone found, or API request failed 2 Usage error (missing/empty option value, missing required parameter, unknown flag) EOF } _expand_short_opts() { # $1 = string of short-opt letters that take a value (e.g. "nXHd"); "" for flag-only scripts # $2..$N = "$@" # Populates _EXPANDED; caller does: set -- "${_EXPANDED[@]}"; unset _EXPANDED local value_opts="$1"; shift _EXPANDED=() local passthru="" local arg local rest local c for arg in "$@"; do if [ -n "$passthru" ]; then _EXPANDED+=("$arg"); continue; fi case "$arg" in --) passthru=1; _EXPANDED+=("$arg") ;; --*|-|"") _EXPANDED+=("$arg") ;; -[a-zA-Z]?*) rest="${arg#-}" while [ -n "$rest" ]; do c="${rest%"${rest#?}"}"; rest="${rest#?}" _EXPANDED+=("-$c") case "$value_opts" in *"$c"*) [ -n "$rest" ] && _EXPANDED+=("$rest") rest="" ;; esac done ;; *) _EXPANDED+=("$arg") ;; esac done } # Initialize local variables with default values from environment variables local jwt="$J_JWT" local shortcode="$J_SHORTCODE" local realm="$J_REALM" local instance="$J_INSTANCE" local target="$J_TARGET" _expand_short_opts "jsrit" "$@" set -- "${_EXPANDED[@]}"; unset _EXPANDED # Parse command-line options while [ $# -gt 0 ]; do case "$1" in -j|--jwt) [ -n "${2-}" ] || { _error "-j|--jwt requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } jwt="$2"; shift 2 ;; --jwt=*) jwt="${1#*=}" [ -n "$jwt" ] || { _error "-j|--jwt requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } shift ;; -s|--shortcode) [ -n "${2-}" ] || { _error "-s|--shortcode requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } shortcode="$2"; shift 2 ;; --shortcode=*) shortcode="${1#*=}" [ -n "$shortcode" ] || { _error "-s|--shortcode requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } shift ;; -r|--realm) [ -n "${2-}" ] || { _error "-r|--realm requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } realm="$2"; shift 2 ;; --realm=*) realm="${1#*=}" [ -n "$realm" ] || { _error "-r|--realm requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } shift ;; -i|--instance) [ -n "${2-}" ] || { _error "-i|--instance requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } instance="$2"; shift 2 ;; --instance=*) instance="${1#*=}" [ -n "$instance" ] || { _error "-i|--instance requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } shift ;; -t|--target) [ -n "${2-}" ] || { _error "-t|--target requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } target="$2"; shift 2 ;; --target=*) target="${1#*=}" [ -n "$target" ] || { _error "-t|--target requires a value. Run \`$SCRIPT_NAME -h\` for usage"; return 2; } shift ;; -h|--help) _show_help return 0 ;; *) _error "Unknown argument '$1'. Run \`$SCRIPT_NAME -h\` for usage"; return 2 ;; esac done # Each parameter is required (via flag or its J_* default); missing any is a usage error if [ -z "$jwt" ]; then _error "jwt is required (use -j or J_JWT). Run \`$SCRIPT_NAME -h\` for usage" return 2 fi if [ -z "$shortcode" ]; then _error "shortcode is required (use -s or J_SHORTCODE). Run \`$SCRIPT_NAME -h\` for usage" return 2 fi if [ -z "$realm" ]; then _error "realm is required (use -r or J_REALM). Run \`$SCRIPT_NAME -h\` for usage" return 2 fi if [ -z "$instance" ]; then _error "instance is required (use -i or J_INSTANCE). Run \`$SCRIPT_NAME -h\` for usage" return 2 fi if [ -z "$target" ]; then _error "target is required (use -t or J_TARGET). Run \`$SCRIPT_NAME -h\` for usage" return 2 fi # Derive other variables local tenant="${realm}_$instance" local organization="f_ecom_$tenant" local path="/cdn/zones/v1/organizations/$organization/zones/info" local hostname="$shortcode.api.commercecloud.salesforce.com" local baseUrl="https://$hostname$path" local limit="$MAX_RESULTS_PER_REQUEST" local offset=0 local response local response_headers local pagination_result_count local pagination_total_count local response_body local target_object while true; do # Call GET /zones/info response="$(curl -fSsiL -X GET "$baseUrl?offset=$offset&limit=$limit" -H 'User-Agent: sfcc-getzone' -H "Authorization: Bearer $jwt" | tr -d '\r')" # Extract response headers response_headers="$(echo "$response" | sed -n '/^HTTP\//,/^$/p' | sed '1d;$d')" # Extract pagination header values using awk pagination_result_count="$(echo "$response_headers" | grep -i "$COUNT_HEADER_NAME" | awk -F': ' '{print $2}')" # Alternatively: cut -d ': ' -f 2 pagination_total_count="$(echo "$response_headers" | grep -i "$TOTAL_HEADER_NAME" | awk -F': ' '{print $2}')" # Alternatively: cut -d ': ' -f 2 # Extract response body response_body="$(echo "$response" | sed -n '/^$/,$p' | sed '1d')" # Use jq to search for the target JSON object target_object="$(echo "$response_body" | jq --arg target "$target" '.data[] | select(.name | contains($target))')" # Check if the target object was found if [ "$target_object" ]; then echo "$target_object" return 0 fi # Check if there are more pages to fetch if [ "$pagination_result_count" -lt "$pagination_total_count" ]; then # Calculate the next offset offset=$((offset + limit)) else _error "Reached the end of pagination without finding the requested zone" _error "Searched for: $target" return 1 fi done ) _find_zone_by_name "$@" __find_zone_by_name_rc=$? unset -f _find_zone_by_name if [ -n "${BASH_SOURCE[0]}" ] && [ "${BASH_SOURCE[0]}" != "$0" ]; then eval "unset __find_zone_by_name_rc; return $__find_zone_by_name_rc" fi eval "unset __find_zone_by_name_rc; exit $__find_zone_by_name_rc"