Files
linux-scripts/rds-snapshot-manager.sh
chiefgeek a1a17e81a1 Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist,
same-site referer bypass, Blackbox-Exporter allowed bot, and all
new exporters, cheat sheets, and automation scripts.
2026-05-25 03:31:08 +02:00

704 lines
29 KiB
Bash
Executable File

#!/usr/bin/env bash
#########################################################################################
#### rds-snapshot-manager.sh — Create, manage, audit, and prune AWS RDS snapshots ####
#### Supports automated creation, cross-region copy, retention, and orphan detection ####
#### Requires: bash 4+, aws-cli v2, jq ####
#### ####
#### Author: Phil Connor ####
#### Contact: contact@mylinux.work ####
#### License: MIT ####
#### Version 1.01 ####
#### ####
#### Usage: ####
#### export AWS_PROFILE="production" ####
#### ./rds-snapshot-manager.sh --snapshot ####
#### ####
#### See --help for all options. ####
#########################################################################################
set -euo pipefail
# ── Defaults ──────────────────────────────────────────────────────────
AWS_REGION="${AWS_REGION:-}"
DB_IDENTIFIER="${DB_IDENTIFIER:-}"
DB_TAG_KEY="${DB_TAG_KEY:-}"
DB_TAG_VALUE="${DB_TAG_VALUE:-}"
RETENTION_DAYS="${RETENTION_DAYS:-30}"
COPY_TO_REGION="${COPY_TO_REGION:-}"
DRY_RUN="${DRY_RUN:-true}"
NO_WAIT="${NO_WAIT:-false}"
RESTORE_INSTANCE_CLASS="${RESTORE_INSTANCE_CLASS:-}"
OUTPUT_FORMAT="${OUTPUT_FORMAT:-text}"
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"
# ── State ─────────────────────────────────────────────────────────────
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
RUN_MODE=""
TARGET_SNAPSHOT=""
START_TIME=""
WARNINGS=0
# ── Colors ────────────────────────────────────────────────────────────
setup_colors() {
if [[ "$COLOR" == "never" ]]; then
RED="" GREEN="" YELLOW="" BLUE="" BOLD="" DIM="" RESET=""
return
fi
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'
else
RED="" GREEN="" YELLOW="" BLUE="" BOLD="" DIM="" RESET=""
fi
}
# ── Logging ───────────────────────────────────────────────────────────
log() { echo -e "${BLUE}[INFO]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; ((WARNINGS++)) || true; }
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
die() { err "$*"; exit 1; }
# ── AWS CLI wrapper ───────────────────────────────────────────────────
aws_cmd() {
local args=("$@")
[[ -n "$AWS_REGION" ]] && args+=(--region "$AWS_REGION")
verbose "aws ${args[*]}"
aws "${args[@]}"
}
# ── Dependency check ──────────────────────────────────────────────────
check_deps() {
for cmd in aws jq; do
if ! command -v "$cmd" &>/dev/null; then
die "${cmd} is required but not installed"
fi
done
if ! aws sts get-caller-identity &>/dev/null; then
die "AWS credentials not configured or expired"
fi
if [[ -z "$AWS_REGION" ]]; then
AWS_REGION=$(aws configure get region 2>/dev/null || echo "")
if [[ -z "$AWS_REGION" ]]; then
die "AWS_REGION is required (set via env var or aws configure)"
fi
fi
verbose "Using region: ${AWS_REGION}"
}
# ── Get DB instance list ──────────────────────────────────────────────
get_db_instances() {
if [[ -n "$DB_IDENTIFIER" ]]; then
echo "$DB_IDENTIFIER"
return
fi
local instances_json
instances_json=$(aws_cmd rds describe-db-instances \
--query 'DBInstances[*].DBInstanceIdentifier' \
--output json 2>/dev/null)
if [[ -n "$DB_TAG_KEY" ]]; then
# Filter by tag — need to check each instance
echo "$instances_json" | jq -r '.[]' | while IFS= read -r db_id; do
local tags_json
local arn
arn=$(aws_cmd rds describe-db-instances \
--db-instance-identifier "$db_id" \
--query 'DBInstances[0].DBInstanceArn' \
--output text 2>/dev/null) || continue
tags_json=$(aws_cmd rds list-tags-for-resource \
--resource-name "$arn" \
--output json 2>/dev/null) || continue
local match
match=$(echo "$tags_json" | jq -r ".TagList[] | select(.Key == \"${DB_TAG_KEY}\" and .Value == \"${DB_TAG_VALUE:-*}\") | .Key" 2>/dev/null)
if [[ -n "$match" ]]; then
echo "$db_id"
fi
done
else
echo "$instances_json" | jq -r '.[]'
fi
}
# ── Get account ID ───────────────────────────────────────────────────
get_account_id() {
aws sts get-caller-identity --query 'Account' --output text
}
# ══════════════════════════════════════════════════════════════════════
# SNAPSHOT MODE
# ══════════════════════════════════════════════════════════════════════
do_snapshot() {
log "Creating RDS snapshots..."
local instances
instances=$(get_db_instances)
if [[ -z "$instances" ]]; then
warn "No DB instances found matching criteria"
return
fi
local db_count
db_count=$(echo "$instances" | wc -l)
log "Found ${db_count} DB instance(s) to snapshot"
local created=0 failed=0
local now
now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
while IFS= read -r db_id; do
[[ -z "$db_id" ]] && continue
verbose "Snapshotting ${db_id}..."
local snap_id
snap_id="rds-snap-${db_id}-$(date +%Y%m%d-%H%M%S)"
local arn
arn=$(aws_cmd rds describe-db-instances \
--db-instance-identifier "$db_id" \
--query 'DBInstances[0].DBInstanceArn' \
--output text 2>/dev/null) || arn=""
if aws_cmd rds create-db-snapshot \
--db-instance-identifier "$db_id" \
--db-snapshot-identifier "$snap_id" \
--tags "Key=CreatedBy,Value=rds-snapshot-manager" \
"Key=CreatedAt,Value=${now}" \
"Key=DBIdentifier,Value=${db_id}" \
--output text &>/dev/null; then
echo -e " ${GREEN}${RESET} ${db_id}${snap_id}"
((created++)) || true
else
echo -e " ${RED}${RESET} ${db_id} — snapshot creation failed"
((failed++)) || true
fi
done <<< "$instances"
# Wait for completion
if [[ "$NO_WAIT" != "true" && "$created" -gt 0 ]]; then
log "Waiting for snapshot(s) to complete (this may take several minutes)..."
while IFS= read -r db_id; do
[[ -z "$db_id" ]] && continue
local snap_id
snap_id="rds-snap-${db_id}-$(date +%Y%m%d-%H%M%S)"
# Wait for the most recent snapshot of this instance
local latest_snap
latest_snap=$(aws_cmd rds describe-db-snapshots \
--db-instance-identifier "$db_id" \
--query 'sort_by(DBSnapshots, &SnapshotCreateTime) | [-1].DBSnapshotIdentifier' \
--output text 2>/dev/null) || continue
if aws_cmd rds wait db-snapshot-available \
--db-snapshot-identifier "$latest_snap" 2>/dev/null; then
verbose "${latest_snap} completed"
else
warn "${latest_snap} did not complete within timeout"
fi
done <<< "$instances"
fi
echo ""
log "Snapshots created: ${created}, failed: ${failed}"
}
# ══════════════════════════════════════════════════════════════════════
# PRUNE MODE
# ══════════════════════════════════════════════════════════════════════
do_prune() {
local cutoff_epoch
cutoff_epoch=$(date -d "-${RETENTION_DAYS} days" +%s 2>/dev/null) || \
cutoff_epoch=$(date -v-"${RETENTION_DAYS}"d +%s 2>/dev/null) || \
die "Could not calculate retention cutoff date"
local cutoff_date
cutoff_date=$(date -d "@${cutoff_epoch}" +%Y-%m-%dT%H:%M:%S 2>/dev/null) || \
cutoff_date=$(date -r "${cutoff_epoch}" +%Y-%m-%dT%H:%M:%S 2>/dev/null)
log "Pruning snapshots older than ${RETENTION_DAYS} days (before ${cutoff_date})"
if [[ "$DRY_RUN" == "true" ]]; then
log "${YELLOW}DRY RUN${RESET} — no snapshots will be deleted. Use --force to delete."
fi
# Get all managed snapshots
local snapshots_json
snapshots_json=$(aws_cmd rds describe-db-snapshots \
--snapshot-type manual \
--query 'DBSnapshots[*].{Id:DBSnapshotIdentifier,DB:DBInstanceIdentifier,Size:AllocatedStorage,Status:Status,Time:SnapshotCreateTime}' \
--output json 2>/dev/null)
local deleted=0 skipped=0 total=0
echo "$snapshots_json" | jq -c '.[]' | while IFS= read -r snap; do
local snap_id snap_time db_id size
snap_id=$(echo "$snap" | jq -r '.Id')
snap_time=$(echo "$snap" | jq -r '.Time')
db_id=$(echo "$snap" | jq -r '.DB')
size=$(echo "$snap" | jq -r '.Size')
# Check if managed by us (check tags)
local is_managed
# shellcheck disable=SC2016
is_managed=$(aws_cmd rds list-tags-for-resource \
--resource-name "arn:aws:rds:${AWS_REGION}:$(get_account_id):snapshot:${snap_id}" \
--query 'TagList[?Key==`CreatedBy` && Value==`rds-snapshot-manager`].Key' \
--output text 2>/dev/null || echo "")
if [[ -z "$is_managed" ]]; then
verbose "Skipping ${snap_id} — not managed by rds-snapshot-manager"
continue
fi
((total++)) || true
local snap_epoch
snap_epoch=$(date -d "${snap_time}" +%s 2>/dev/null) || \
snap_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "${snap_time:0:19}" +%s 2>/dev/null) || continue
if [[ "$snap_epoch" -lt "$cutoff_epoch" ]]; then
local age_days=$(( ($(date +%s) - snap_epoch) / 86400 ))
if [[ "$DRY_RUN" == "true" ]]; then
echo -e " ${YELLOW}${RESET} ${snap_id} (${db_id}, ${size}G, ${age_days}d) — would delete"
else
if aws_cmd rds delete-db-snapshot \
--db-snapshot-identifier "$snap_id" &>/dev/null; then
echo -e " ${RED}${RESET} ${snap_id} (${db_id}, ${size}G, ${age_days}d) — deleted"
((deleted++)) || true
else
warn "Failed to delete ${snap_id}"
fi
fi
else
((skipped++)) || true
verbose "Keeping ${snap_id} — within retention"
fi
done
echo ""
if [[ "$DRY_RUN" == "true" ]]; then
log "Dry run complete. Use --force to actually delete snapshots."
else
log "Deleted: ${deleted}, kept: ${skipped}"
fi
}
# ══════════════════════════════════════════════════════════════════════
# COPY-REGION MODE
# ══════════════════════════════════════════════════════════════════════
do_copy_region() {
if [[ -z "$COPY_TO_REGION" ]]; then
die "No target region specified. Use --copy-region REGION"
fi
log "Copying latest snapshots to ${COPY_TO_REGION}..."
local instances
instances=$(get_db_instances)
if [[ -z "$instances" ]]; then
warn "No DB instances found"
return
fi
local copied=0 failed=0
while IFS= read -r db_id; do
[[ -z "$db_id" ]] && continue
local latest_snap
latest_snap=$(aws_cmd rds describe-db-snapshots \
--db-instance-identifier "$db_id" \
--snapshot-type manual \
--query 'sort_by(DBSnapshots, &SnapshotCreateTime) | [-1].DBSnapshotIdentifier' \
--output text 2>/dev/null)
if [[ -z "$latest_snap" || "$latest_snap" == "None" ]]; then
warn "No snapshots found for ${db_id}"
continue
fi
local source_arn
source_arn="arn:aws:rds:${AWS_REGION}:$(get_account_id):snapshot:${latest_snap}"
local target_snap="dr-${latest_snap}"
verbose "Copying ${latest_snap}${COPY_TO_REGION}"
if aws rds copy-db-snapshot \
--source-db-snapshot-identifier "$source_arn" \
--target-db-snapshot-identifier "$target_snap" \
--region "$COPY_TO_REGION" \
--copy-tags \
--output text &>/dev/null; then
echo -e " ${GREEN}${RESET} ${latest_snap}${COPY_TO_REGION} (${target_snap})"
((copied++)) || true
else
echo -e " ${RED}${RESET} ${latest_snap} — copy failed"
((failed++)) || true
fi
done <<< "$instances"
echo ""
log "Copied: ${copied}, failed: ${failed}"
}
# ══════════════════════════════════════════════════════════════════════
# AUDIT MODE
# ══════════════════════════════════════════════════════════════════════
do_audit() {
log "Auditing RDS snapshots in ${AWS_REGION}..."
# Get all manual snapshots
local snapshots_json
snapshots_json=$(aws_cmd rds describe-db-snapshots \
--snapshot-type manual \
--query 'DBSnapshots[*].{Id:DBSnapshotIdentifier,DB:DBInstanceIdentifier,Size:AllocatedStorage,Status:Status,Time:SnapshotCreateTime}' \
--output json 2>/dev/null)
local total
total=$(echo "$snapshots_json" | jq 'length')
if [[ "$total" -eq 0 ]]; then
log "No manual snapshots found"
return
fi
# Display snapshot inventory
echo ""
printf " ${BOLD}%-30s %-20s %8s %6s %s${RESET}\n" "SNAPSHOT" "DB INSTANCE" "SIZE" "AGE" "STATUS"
printf " %s\n" "$(printf '%.0s─' {1..80})"
# Get list of current DB instances
local current_instances
current_instances=$(aws_cmd rds describe-db-instances \
--query 'DBInstances[*].DBInstanceIdentifier' \
--output text 2>/dev/null | tr '\t' '\n')
echo "$snapshots_json" | jq -c '.[]' | while IFS= read -r snap; do
local snap_id db_id size status snap_time
snap_id=$(echo "$snap" | jq -r '.Id')
db_id=$(echo "$snap" | jq -r '.DB')
size=$(echo "$snap" | jq -r '.Size')
status=$(echo "$snap" | jq -r '.Status')
snap_time=$(echo "$snap" | jq -r '.Time')
local snap_epoch age_days
snap_epoch=$(date -d "${snap_time}" +%s 2>/dev/null) || snap_epoch=0
age_days=$(( ($(date +%s) - snap_epoch) / 86400 ))
local label="manual"
if ! echo "$current_instances" | grep -qx "$db_id"; then
label="orphan"
fi
printf " %-30s %-20s %6s G %4sd %s\n" \
"${snap_id:0:30}" "${db_id:0:20}" "$size" "$age_days" "$label"
done
# Cost estimate
local total_gb
total_gb=$(echo "$snapshots_json" | jq '[.[].Size] | add // 0')
local est_cost
est_cost=$(awk "BEGIN { printf \"%.2f\", $total_gb * 0.05 }")
echo ""
echo -e " ${BOLD}Summary${RESET}"
echo " Total snapshots: ${total}"
echo " Total storage: ${total_gb} GiB"
echo " Est. monthly cost: \$${est_cost}"
# Unprotected instances
echo ""
echo -e " ${BOLD}DB Instances Without Recent Snapshots (>${RETENTION_DAYS}d)${RESET}"
local db_instances
db_instances=$(aws_cmd rds describe-db-instances \
--query 'DBInstances[*].{Id:DBInstanceIdentifier,Size:AllocatedStorage}' \
--output json 2>/dev/null)
echo "$db_instances" | jq -c '.[]' | while IFS= read -r db; do
local db_id db_size
db_id=$(echo "$db" | jq -r '.Id')
db_size=$(echo "$db" | jq -r '.Size')
local latest_time
latest_time=$(aws_cmd rds describe-db-snapshots \
--db-instance-identifier "$db_id" \
--snapshot-type manual \
--query 'sort_by(DBSnapshots, &SnapshotCreateTime) | [-1].SnapshotCreateTime' \
--output text 2>/dev/null)
if [[ -z "$latest_time" || "$latest_time" == "None" ]]; then
echo -e " ${RED}${RESET} ${db_id} (${db_size} GiB) — no snapshots"
else
local snap_epoch age_days
snap_epoch=$(date -d "${latest_time}" +%s 2>/dev/null) || snap_epoch=0
age_days=$(( ($(date +%s) - snap_epoch) / 86400 ))
if [[ "$age_days" -gt "$RETENTION_DAYS" ]]; then
echo -e " ${YELLOW}!${RESET} ${db_id} (${db_size} GiB) — last snapshot ${age_days}d ago"
fi
fi
done
echo ""
log "Audit complete"
}
# ══════════════════════════════════════════════════════════════════════
# RESTORE MODE
# ══════════════════════════════════════════════════════════════════════
do_restore() {
if [[ -z "$TARGET_SNAPSHOT" ]]; then
die "No snapshot specified for restore"
fi
log "Restoring from snapshot ${TARGET_SNAPSHOT}..."
# Get snapshot info
local snap_info
snap_info=$(aws_cmd rds describe-db-snapshots \
--db-snapshot-identifier "$TARGET_SNAPSHOT" \
--query 'DBSnapshots[0].{DB:DBInstanceIdentifier,Size:AllocatedStorage,Engine:Engine,EngineVer:EngineVersion}' \
--output json 2>/dev/null) || die "Snapshot not found: ${TARGET_SNAPSHOT}"
local source_db engine engine_ver snap_size
source_db=$(echo "$snap_info" | jq -r '.DB')
engine=$(echo "$snap_info" | jq -r '.Engine')
engine_ver=$(echo "$snap_info" | jq -r '.EngineVer')
snap_size=$(echo "$snap_info" | jq -r '.Size')
local new_db_id
new_db_id="restored-${source_db}-$(date +%Y%m%d-%H%M%S)"
local restore_args=(
rds restore-db-instance-from-db-snapshot
--db-instance-identifier "$new_db_id"
--db-snapshot-identifier "$TARGET_SNAPSHOT"
--tags "Key=CreatedBy,Value=rds-snapshot-manager"
"Key=RestoredFrom,Value=${TARGET_SNAPSHOT}"
"Key=SourceDB,Value=${source_db}"
)
[[ -n "$RESTORE_INSTANCE_CLASS" ]] && restore_args+=(--db-instance-class "$RESTORE_INSTANCE_CLASS")
if aws_cmd "${restore_args[@]}" --output text &>/dev/null; then
echo -e " ${GREEN}${RESET} Restoring to ${new_db_id}"
echo " Source snapshot: ${TARGET_SNAPSHOT}"
echo " Engine: ${engine} ${engine_ver}"
echo " Size: ${snap_size} GiB"
if [[ "$NO_WAIT" != "true" ]]; then
log "Waiting for instance to become available (this may take several minutes)..."
if aws_cmd rds wait db-instance-available \
--db-instance-identifier "$new_db_id" 2>/dev/null; then
echo -e " ${GREEN}${RESET} Instance ${new_db_id} is available"
else
warn "Instance did not become available within timeout"
fi
fi
else
die "Failed to restore from snapshot"
fi
}
# ══════════════════════════════════════════════════════════════════════
# LIST MODE
# ══════════════════════════════════════════════════════════════════════
do_list() {
local query_args=(rds describe-db-snapshots --snapshot-type manual)
[[ -n "$DB_IDENTIFIER" ]] && query_args+=(--db-instance-identifier "$DB_IDENTIFIER")
local snapshots_json
snapshots_json=$(aws_cmd "${query_args[@]}" \
--query 'sort_by(DBSnapshots, &SnapshotCreateTime) | reverse(@) | [*].{Id:DBSnapshotIdentifier,DB:DBInstanceIdentifier,Size:AllocatedStorage,Status:Status,Time:SnapshotCreateTime,Engine:Engine}' \
--output json 2>/dev/null)
local total
total=$(echo "$snapshots_json" | jq 'length')
if [[ "$total" -eq 0 ]]; then
log "No snapshots found"
return
fi
if [[ "$OUTPUT_FORMAT" == "json" ]]; then
echo "$snapshots_json" | jq '.'
return
fi
echo ""
printf " ${BOLD}%-30s %-18s %6s %-10s %-22s %s${RESET}\n" "SNAPSHOT" "DB INSTANCE" "SIZE" "STATUS" "CREATED" "ENGINE"
printf " %s\n" "$(printf '%.0s─' {1..100})"
echo "$snapshots_json" | jq -c '.[]' | while IFS= read -r snap; do
local snap_id db_id size status snap_time engine
snap_id=$(echo "$snap" | jq -r '.Id')
db_id=$(echo "$snap" | jq -r '.DB')
size=$(echo "$snap" | jq -r '.Size')
status=$(echo "$snap" | jq -r '.Status')
snap_time=$(echo "$snap" | jq -r '.Time' | cut -c1-19)
engine=$(echo "$snap" | jq -r '.Engine')
printf " %-30s %-18s %4s G %-10s %-22s %s\n" \
"${snap_id:0:30}" "${db_id:0:18}" "$size" "$status" "$snap_time" "$engine"
done
echo ""
log "Total: ${total} snapshot(s)"
}
# ══════════════════════════════════════════════════════════════════════
# HELP
# ══════════════════════════════════════════════════════════════════════
show_help() {
cat <<EOF
Usage: $SCRIPT_NAME [MODE] [OPTIONS]
Manage AWS RDS snapshots — create, prune, copy, audit, restore, and list.
MODES:
--snapshot Create snapshots of RDS instances
--prune Delete old managed snapshots (dry-run by default)
--copy-region REGION Copy latest snapshots to another region
--audit Snapshot health check and cost report
--restore SNAP_ID Restore a DB instance from a snapshot
--list List snapshots
OPTIONS:
--db-identifier ID Target a specific DB instance
--tag KEY=VALUE Filter instances by tag
--retention-days N Retention period in days (default: $RETENTION_DAYS)
--format FORMAT Output: text (default), json, prometheus
--force Actually delete in prune mode (default is dry-run)
--no-wait Don't wait for completion
--instance-class CLASS DB instance class for restore
--verbose Debug output
--no-color Disable colored output
--help, -h Show this help
ENVIRONMENT VARIABLES:
AWS_PROFILE AWS CLI profile
AWS_REGION AWS region
DB_IDENTIFIER Target DB instance identifier
DB_TAG_KEY Filter instances by tag key
DB_TAG_VALUE Filter instances by tag value
RETENTION_DAYS Days to retain snapshots (default: 30)
COPY_TO_REGION Target region for cross-region copy
DRY_RUN Dry-run for prune mode (default: true)
NO_WAIT Don't wait for completion (default: false)
RESTORE_INSTANCE_CLASS DB instance class for restore
OUTPUT_FORMAT Output format (default: text)
VERBOSE Debug output (default: false)
COLOR Color mode: auto, always, never
EXAMPLES:
# Snapshot all DB instances
./$SCRIPT_NAME --snapshot
# Snapshot specific instance
./$SCRIPT_NAME --snapshot --db-identifier mydb-prod
# Dry-run prune
./$SCRIPT_NAME --prune --retention-days 14
# Actually delete old snapshots
./$SCRIPT_NAME --prune --retention-days 14 --force
# Copy to us-west-2 for DR
./$SCRIPT_NAME --copy-region us-west-2
# Audit snapshots
./$SCRIPT_NAME --audit
# Restore from snapshot
./$SCRIPT_NAME --restore rds-snap-mydb-20260410
# List all snapshots
./$SCRIPT_NAME --list
EOF
}
# ══════════════════════════════════════════════════════════════════════
# MAIN
# ══════════════════════════════════════════════════════════════════════
main() {
while [[ $# -gt 0 ]]; do
case "$1" in
--snapshot) RUN_MODE="snapshot"; shift ;;
--prune) RUN_MODE="prune"; shift ;;
--copy-region) RUN_MODE="copy-region"; COPY_TO_REGION="$2"; shift 2 ;;
--audit) RUN_MODE="audit"; shift ;;
--restore) RUN_MODE="restore"; TARGET_SNAPSHOT="$2"; shift 2 ;;
--list) RUN_MODE="list"; shift ;;
--db-identifier) DB_IDENTIFIER="$2"; shift 2 ;;
--tag)
local tag_pair="$2"
DB_TAG_KEY="${tag_pair%%=*}"
DB_TAG_VALUE="${tag_pair#*=}"
shift 2
;;
--retention-days) RETENTION_DAYS="$2"; shift 2 ;;
--format) OUTPUT_FORMAT="$2"; shift 2 ;;
--force) DRY_RUN="false"; shift ;;
--no-wait) NO_WAIT="true"; shift ;;
--instance-class) RESTORE_INSTANCE_CLASS="$2"; shift 2 ;;
--verbose) VERBOSE="true"; shift ;;
--no-color) COLOR="never"; shift ;;
--help|-h) show_help; exit 0 ;;
*) die "Unknown option: $1 (see --help)" ;;
esac
done
setup_colors
if [[ -z "$RUN_MODE" ]]; then err "No mode specified"; echo ""; show_help; exit 1; fi
START_TIME=$(date +%s)
echo ""
echo -e "${BOLD}RDS Snapshot Manager${RESET}"
echo "Region: ${AWS_REGION:-$(aws configure get region 2>/dev/null || echo 'default')}"
echo "Mode: ${RUN_MODE}"
echo "Time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo ""
check_deps
case "$RUN_MODE" in
snapshot) do_snapshot ;;
prune) do_prune ;;
copy-region) do_copy_region ;;
audit) do_audit ;;
restore) do_restore ;;
list) do_list ;;
esac
local end_time
end_time=$(date +%s)
local duration=$(( end_time - START_TIME ))
log "Completed in ${duration}s"
}
main "$@"