#!/usr/bin/env bash set -euo pipefail # ------------------------------------------------------------ # delete-vids-devnet.sh # ------------------------------------------------------------ VERSION="1.0.0" HOST_TEMPLATE="devnet-node-%d.qortal.link" HOST_FIXED="" PORT_START=22221 PORT_END=22227 REMOTE_USER="${USER}" REMOTE_HOME="/home/${REMOTE_USER}" SSH_RETRIES=4 SSH_DELAY=5 NODE_SPEC=() PRIMARY_NODE=4 usage() { cat <&2; } warn() { log "WARNING: $*"; } parse_ports() { local spec="$1" [[ "$spec" =~ ^([0-9]+)-([0-9]+)$ ]] || { echo "Invalid --ports (use A-B)" >&2; exit 1; } PORT_START="${BASH_REMATCH[1]}" PORT_END="${BASH_REMATCH[2]}" (( PORT_START <= PORT_END )) || { echo "--ports start must be <= end" >&2; exit 1; } } add_node_spec() { local spec="$1" spec="${spec//[[:space:]]/}" [[ "$spec" =~ ^[0-9]+$ ]] || { echo "Invalid node spec: $spec" >&2; exit 1; } NODE_SPEC+=( "$spec" ) } parse_nodes_list() { local list="$1" IFS=',' read -r -a parts <<< "$list" for part in "${parts[@]}"; do [[ -n "$part" ]] || continue add_node_spec "$part" done } node_to_port() { local node="$1" echo $(( PORT_START + node - 1 )) } host_for_port() { local port="$1" if [[ -n "$HOST_FIXED" ]]; then echo "$HOST_FIXED" return 0 fi local idx=$((port - PORT_START + 1)) if (( idx < 1 )); then echo "Invalid port ${port} for template mapping (PORT_START=${PORT_START})" >&2 return 1 fi printf "$HOST_TEMPLATE" "$idx" } while [[ $# -gt 0 ]]; do case "$1" in --host) HOST_FIXED="${2:-}"; shift 2;; --host-template) HOST_TEMPLATE="${2:-}"; shift 2;; --ports) parse_ports "${2:-}"; shift 2;; --node) add_node_spec "${2:-}"; shift 2;; --nodes) parse_nodes_list "${2:-}"; shift 2;; -h|--help) usage; exit 0;; --) shift; break;; -[0-9]*) add_node_spec "${1:1}"; shift;; [0-9]*) add_node_spec "$1"; shift;; *) echo "Unknown arg: $1" >&2; usage; exit 1;; esac done NODE_COUNT=$(( PORT_END - PORT_START + 1 )) (( NODE_COUNT > 0 )) || { echo "Invalid port range ${PORT_START}-${PORT_END}" >&2; exit 1; } TARGET_NODES_RAW=() if (( ${#NODE_SPEC[@]} == 0 )); then for ((i=1; i<=NODE_COUNT; i++)); do TARGET_NODES_RAW+=( "$i" ) done else mapfile -t TARGET_NODES_RAW < <(printf '%s\n' "${NODE_SPEC[@]}" | awk 'NF' | sort -n | uniq) fi TARGET_NODES=() for node in "${TARGET_NODES_RAW[@]}"; do if [[ ! "$node" =~ ^[0-9]+$ ]]; then echo "Invalid node index: $node" >&2 exit 1 fi if (( node == PRIMARY_NODE )); then warn "Skipping primary node ${PRIMARY_NODE} per policy" continue fi if (( node < 1 || node > NODE_COUNT )); then echo "Node ${node} is outside the available range 1-${NODE_COUNT}" >&2 exit 1 fi TARGET_NODES+=( "$node" ) done if (( ${#TARGET_NODES[@]} == 0 )); then echo "No target nodes left after applying exclusions (primary node ${PRIMARY_NODE} is protected)." >&2 exit 1 fi log "Primary node ${PRIMARY_NODE} is protected and will be skipped." log "Target nodes: ${TARGET_NODES[*]}" log "Port range: ${PORT_START}-${PORT_END}" if [[ -n "$HOST_FIXED" ]]; then log "Host: ${HOST_FIXED}" else log "Host template: ${HOST_TEMPLATE}" fi log "SSH retries: ${SSH_RETRIES}, start delay ${SSH_DELAY}s" run_delete_sequence() { local node="$1" local port="$2" local host="$3" local target="${REMOTE_USER}@${host}" local attempt=1 local delay="$SSH_DELAY" while (( attempt <= SSH_RETRIES )); do log "[node ${node}] running delete commands (attempt ${attempt}/${SSH_RETRIES})" if ssh -p"${port}" "${target}" bash <<'EOF' set -euo pipefail echo "Deleteing Birds Video" curl -X DELETE \ http://127.0.0.1:22391/arbitrary/resource/VIDEO/Q-Tube/MYTEST2_vid_-the-funniest-birds_sErSoP \ -H 'accept: text/plain' \ -H 'X-API-KEY: 3emLj1L5M1e8uQDob8bF3b' echo "Deleteing Q-Tube May 15 video" curl -X DELETE \ http://127.0.0.1:22391/arbitrary/resource/VIDEO/Q-Tube/MYTEST2_vid_q-tube-may-15_0cT8id \ -H 'accept: text/plain' \ -H 'X-API-KEY: 3emLj1L5M1e8uQDob8bF3b' echo "Deleteing Blood Machines" curl -X DELETE \ http://127.0.0.1:22391/arbitrary/resource/VIDEO/Q-Tube/MYTEST2_vid_blood-machines-chapter-two-cor_STChYK \ -H 'accept: text/plain' \ -H 'X-API-KEY: 3emLj1L5M1e8uQDob8bF3b' echo "Deleteing Batman" curl -X DELETE \ http://127.0.0.1:22391/arbitrary/resource/VIDEO/Q-Tube/MYTEST2_vid_batman_1j2qoI \ -H 'accept: text/plain' \ -H 'X-API-KEY: 3emLj1L5M1e8uQDob8bF3b' EOF then log "[node ${node}] delete sequence succeeded" return 0 fi warn "[node ${node}] delete attempt ${attempt} failed" (( attempt++ )) sleep "$delay" delay=$(( delay * 2 )) done warn "[node ${node}] delete sequence failed after ${SSH_RETRIES} attempts" return 1 } for node in "${TARGET_NODES[@]}"; do port="$(node_to_port "$node")" host="$(host_for_port "$port")" || { warn "[node ${node}] host mapping failed; skipping"; continue; } log "==================== node ${node} (port ${port}) ====================" log "[node ${node}] host: ${host}" if ! run_delete_sequence "$node" "$port" "$host"; then warn "[node ${node}] delete commands failed; moving to next node" continue fi log "[node ${node}] done" done log "All nodes processed."