Last active
July 2, 2025 18:07
-
-
Save rleap-m/9efc2f1d3eb6afa2b44936a7ddb518e6 to your computer and use it in GitHub Desktop.
Fetch and report MSR 4 replication executions for rules matching a prefix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Defaults (can be overridden by CLI flags) | |
| HARBOR_URL="${HARBOR_URL:-}" | |
| HARBOR_USER="${HARBOR_USER:-}" | |
| HARBOR_PWD="${HARBOR_PWD:-}" | |
| PREFIX="migration-rule-" | |
| PAGE_SIZE=100 | |
| MODE="all" | |
| LATEST_ONLY="false" | |
| # Argument parsing | |
| for arg in "$@"; do | |
| case "$arg" in | |
| --json) MODE="json" ;; | |
| --summary) MODE="summary" ;; | |
| --prefix=*) PREFIX="${arg#--prefix=}" ;; | |
| --url=*) HARBOR_URL="${arg#--url=}" ;; | |
| --user=*) HARBOR_USER="${arg#--user=}" ;; | |
| --pwd=*) HARBOR_PWD="${arg#--pwd=}" ;; | |
| --latest-execution|--latest) LATEST_ONLY="true" ;; | |
| --help|-h) | |
| echo "Fetch and report MSR 4 replication executions for rules matching a prefix." | |
| echo | |
| echo "By default, the script outputs both structured JSON and a human-readable summary." | |
| echo "You can limit output to just one or the other, and override defaults via flags or env vars." | |
| echo | |
| echo "Usage: $0 [options]" | |
| echo | |
| echo "Options:" | |
| echo " --json Only print structured JSON output" | |
| echo " --summary Only print human-readable summary" | |
| echo " --latest-execution Show only the latest execution per replication policy" | |
| echo " --prefix=VALUE Replication rule prefix to match (default: migration-rule-)" | |
| echo " --url=URL MSR 4 base URL (or use HARBOR_URL env)" | |
| echo " --user=USER MSR 4 username (or use HARBOR_USER env)" | |
| echo " --pwd=PASSWORD MSR 4 password (or use HARBOR_PWD env)" | |
| echo " --help, -h Show this help message" | |
| echo | |
| echo "Examples:" | |
| echo " $0 --summary --prefix=prod-" | |
| echo " $0 --json --url=https://msr4.example.com --user=admin --pwd=secret --latest-execution" | |
| exit 0 | |
| ;; | |
| *) | |
| echo "Unknown option: $arg" | |
| echo "Run '$0 --help' for usage." | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # Validate required credentials | |
| if [[ -z "$HARBOR_URL" || -z "$HARBOR_USER" || -z "$HARBOR_PWD" ]]; then | |
| echo "ERROR: HARBOR_URL, HARBOR_USER, and HARBOR_PWD must be set (via env or --url/--user/--pwd)." | |
| exit 1 | |
| fi | |
| # Status message (suppress if --json only) | |
| if [[ "$MODE" == "all" || "$MODE" == "summary" ]]; then | |
| echo "Fetching policies with prefix '$PREFIX'..." | |
| fi | |
| # Prepare output buckets | |
| TMPDIR=$(mktemp -d) | |
| declare -A STATUS_FILES | |
| for s in Succeed InProgress Failed Stopped Others; do | |
| STATUS_FILES[$s]="$TMPDIR/${s,,}.json" | |
| > "${STATUS_FILES[$s]}" | |
| done | |
| TOTAL_COUNT=0 | |
| # Paginate all replication policies | |
| POLICIES="[]" | |
| PAGE=1 | |
| while :; do | |
| RESP=$(curl -s -u "$HARBOR_USER:$HARBOR_PWD" \ | |
| "$HARBOR_URL/api/v2.0/replication/policies?page=$PAGE&page_size=$PAGE_SIZE") | |
| COUNT=$(echo "$RESP" | jq length) | |
| POLICIES=$(jq -s 'add' <(echo "$POLICIES") <(echo "$RESP")) | |
| (( COUNT < PAGE_SIZE )) && break | |
| PAGE=$((PAGE + 1)) | |
| done | |
| # Filter policies by prefix | |
| FILTERED_POLICIES=$(echo "$POLICIES" | jq -c ".[] | select(.name | startswith(\"$PREFIX\")) | {id: .id, name: .name}") | |
| # Loop over filtered policies | |
| while IFS= read -r policy; do | |
| POLICY_ID=$(jq -r '.id' <<< "$policy") | |
| POLICY_NAME=$(jq -r '.name' <<< "$policy") | |
| if [[ "$LATEST_ONLY" == "true" ]]; then | |
| EXEC_PAGE=$(curl -s -u "$HARBOR_USER:$HARBOR_PWD" \ | |
| "$HARBOR_URL/api/v2.0/replication/executions?policy_id=$POLICY_ID&page=1&page_size=1") | |
| EXEC_COUNT=$(echo "$EXEC_PAGE" | jq length) | |
| TOTAL_COUNT=$((TOTAL_COUNT + EXEC_COUNT)) | |
| [[ "$EXEC_COUNT" -eq 0 ]] && continue | |
| EXEC=$(echo "$EXEC_PAGE" | jq ".[0]") | |
| STATUS=$(echo "$EXEC" | jq -r '.status') | |
| START_TIME=$(echo "$EXEC" | jq -r '.start_time') | |
| END_TIME=$(echo "$EXEC" | jq -r '.end_time') | |
| EXEC_ID=$(echo "$EXEC" | jq -r '.id') | |
| ENTRY=$(cat <<EOF | envsubst | |
| { | |
| "execution_id": "$EXEC_ID", | |
| "policy_name": "$POLICY_NAME", | |
| "status": "$STATUS", | |
| "start_time": "$START_TIME", | |
| "end_time": "$END_TIME" | |
| } | |
| EOF | |
| ) | |
| case "$STATUS" in | |
| Succeed) echo "$ENTRY" >> "${STATUS_FILES[Succeed]}" ;; | |
| InProgress) echo "$ENTRY" >> "${STATUS_FILES[InProgress]}" ;; | |
| Failed) echo "$ENTRY" >> "${STATUS_FILES[Failed]}" ;; | |
| Stopped) echo "$ENTRY" >> "${STATUS_FILES[Stopped]}" ;; | |
| *) echo "$ENTRY" >> "${STATUS_FILES[Others]}" ;; | |
| esac | |
| else | |
| PAGE=1 | |
| while :; do | |
| EXEC_PAGE=$(curl -s -u "$HARBOR_USER:$HARBOR_PWD" \ | |
| "$HARBOR_URL/api/v2.0/replication/executions?policy_id=$POLICY_ID&page=$PAGE&page_size=$PAGE_SIZE") | |
| EXEC_COUNT=$(echo "$EXEC_PAGE" | jq length) | |
| TOTAL_COUNT=$((TOTAL_COUNT + EXEC_COUNT)) | |
| (( EXEC_COUNT == 0 )) && break | |
| for ((i = 0; i < EXEC_COUNT; i++)); do | |
| EXEC=$(echo "$EXEC_PAGE" | jq ".[$i]") | |
| STATUS=$(echo "$EXEC" | jq -r '.status') | |
| START_TIME=$(echo "$EXEC" | jq -r '.start_time') | |
| END_TIME=$(echo "$EXEC" | jq -r '.end_time') | |
| EXEC_ID=$(echo "$EXEC" | jq -r '.id') | |
| ENTRY=$(cat <<EOF | envsubst | |
| { | |
| "execution_id": "$EXEC_ID", | |
| "policy_name": "$POLICY_NAME", | |
| "status": "$STATUS", | |
| "start_time": "$START_TIME", | |
| "end_time": "$END_TIME" | |
| } | |
| EOF | |
| ) | |
| case "$STATUS" in | |
| Succeed) echo "$ENTRY" >> "${STATUS_FILES[Succeed]}" ;; | |
| InProgress) echo "$ENTRY" >> "${STATUS_FILES[InProgress]}" ;; | |
| Failed) echo "$ENTRY" >> "${STATUS_FILES[Failed]}" ;; | |
| Stopped) echo "$ENTRY" >> "${STATUS_FILES[Stopped]}" ;; | |
| *) echo "$ENTRY" >> "${STATUS_FILES[Others]}" ;; | |
| esac | |
| done | |
| (( EXEC_COUNT < PAGE_SIZE )) && break | |
| PAGE=$((PAGE + 1)) | |
| done | |
| fi | |
| done <<< "$FILTERED_POLICIES" | |
| # Load JSON arrays | |
| load_json_array() { | |
| local file="$1" | |
| [[ -s "$file" ]] && jq -s '.' "$file" || echo "[]" | |
| } | |
| # Output JSON | |
| if [[ "$MODE" == "all" || "$MODE" == "json" ]]; then | |
| echo | |
| echo "=== Replication Execution Status JSON ===" | |
| jq -n \ | |
| --argjson succeed "$(load_json_array "${STATUS_FILES[Succeed]}")" \ | |
| --argjson inprogress "$(load_json_array "${STATUS_FILES[InProgress]}")" \ | |
| --argjson failed "$(load_json_array "${STATUS_FILES[Failed]}")" \ | |
| --argjson stopped "$(load_json_array "${STATUS_FILES[Stopped]}")" \ | |
| --argjson others "$(load_json_array "${STATUS_FILES[Others]}")" \ | |
| '{ | |
| Succeed: $succeed, | |
| InProgress: $inprogress, | |
| Failed: $failed, | |
| Stopped: $stopped, | |
| Others: $others | |
| }' | |
| fi | |
| # Output Summary | |
| if [[ "$MODE" == "all" || "$MODE" == "summary" ]]; then | |
| SUCCEED=$(load_json_array "${STATUS_FILES[Succeed]}") | |
| INPROGRESS=$(load_json_array "${STATUS_FILES[InProgress]}") | |
| FAILED=$(load_json_array "${STATUS_FILES[Failed]}") | |
| STOPPED=$(load_json_array "${STATUS_FILES[Stopped]}") | |
| OTHERS=$(load_json_array "${STATUS_FILES[Others]}") | |
| SUCCEED_COUNT=$(jq length <<< "$SUCCEED") | |
| INPROGRESS_COUNT=$(jq length <<< "$INPROGRESS") | |
| FAILED_COUNT=$(jq length <<< "$FAILED") | |
| STOPPED_COUNT=$(jq length <<< "$STOPPED") | |
| OTHERS_COUNT=$(jq length <<< "$OTHERS") | |
| pct() { | |
| local count=$1 | |
| local total=$2 | |
| [[ "$total" -eq 0 ]] && echo " 0%" && return | |
| printf "%4.1f%%" "$(bc -l <<< "100 * $count / $total")" | |
| } | |
| echo | |
| echo "=== Replication Summary ===" | |
| printf "%-16s: %5d\n" "Total executions" "$TOTAL_COUNT" | |
| printf "%-16s: %5d (%s)\n" "Succeeded" "$SUCCEED_COUNT" "$(pct $SUCCEED_COUNT $TOTAL_COUNT)" | |
| printf "%-16s: %5d (%s)\n" "In Progress" "$INPROGRESS_COUNT" "$(pct $INPROGRESS_COUNT $TOTAL_COUNT)" | |
| printf "%-16s: %5d (%s)\n" "Failed" "$FAILED_COUNT" "$(pct $FAILED_COUNT $TOTAL_COUNT)" | |
| printf "%-16s: %5d (%s)\n" "Stopped" "$STOPPED_COUNT" "$(pct $STOPPED_COUNT $TOTAL_COUNT)" | |
| printf "%-16s: %5d (%s)\n" "Others" "$OTHERS_COUNT" "$(pct $OTHERS_COUNT $TOTAL_COUNT)" | |
| fi | |
| rm -rf "$TMPDIR" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment