Skip to content

Instantly share code, notes, and snippets.

@rleap-m
Last active July 2, 2025 18:07
Show Gist options
  • Save rleap-m/9efc2f1d3eb6afa2b44936a7ddb518e6 to your computer and use it in GitHub Desktop.
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
#!/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