mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 16:54:32 +00:00
feat(scripts): introduce DNS sync script for Samba AD and hosts management
- Added `init-prole-dns.sh` to sync host records to Samba AD DNS. - Included a fallback `hosts.txt` for static entries when Postgres is unavailable. - Script supports operations such as start, stop, sync, status, and flush. - Integrated cron-based hourly sync functionality.
This commit is contained in:
parent
b735a1df13
commit
4c0c593b34
15
etc/hosts.txt
Normal file
15
etc/hosts.txt
Normal file
@ -0,0 +1,15 @@
|
||||
myrddin.prole.org 10.0.0.3
|
||||
raspberry.prole.org 10.0.0.4
|
||||
pi.prole.org 10.0.0.5
|
||||
synology.prole.org 10.0.0.203
|
||||
morgoth.prole.org 10.0.0.204
|
||||
zinfandel.prole.org 10.0.0.205
|
||||
aventage.prole.org 10.0.0.206
|
||||
retropie.prole.org 10.0.0.207
|
||||
fairyland.prole.org 10.0.0.208
|
||||
k8s.prole.org zinfandel.prole.org
|
||||
mc.prole.org 73.15.20.166
|
||||
morana.prole.org 10.0.0.66
|
||||
ollama.prole.org 73.15.20.166
|
||||
svc.prole.org 73.15.20.166
|
||||
www.prole.org ghs.googlehosted.com
|
||||
532
prole-dns/init-prole-dns.sh
Normal file
532
prole-dns/init-prole-dns.sh
Normal file
@ -0,0 +1,532 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# init-prole-dns.sh
|
||||
# Sync prole.org host records into Samba AD DNS using samba-tool.
|
||||
#
|
||||
# Host source:
|
||||
# 1) Postgres (preferred when available):
|
||||
# SELECT host_name, ip_address FROM prole.hosts;
|
||||
# 2) Fallback file:
|
||||
# /etc/prole-dns-sync/hosts.txt (one hostname per line; FQDN or short)
|
||||
#
|
||||
# Commands:
|
||||
# start - run sync now + install hourly cron job
|
||||
# stop - remove cron job
|
||||
# status - show last run time, last exit, and journal messages
|
||||
# sync - run one sync pass
|
||||
# flush - clear local state (forces "unknown" status); does NOT delete DNS records
|
||||
# list|show|details - show configured hostnames and detected DC info
|
||||
#
|
||||
# Options:
|
||||
# -db=HOST:PORT/DBNAME default: localhost:5432/prole-db
|
||||
#
|
||||
# Environment overrides (optional):
|
||||
# AD_DNS_ZONE default: prole.org
|
||||
# AD_DNS_SERVER default: auto-detect (hostname -f)
|
||||
# AD_DNS_SERVER_IP default: auto-detect via getent hosts
|
||||
# PUBLIC_DNS_SERVER default: first NS of prole.org from system resolv OR "ns1.name.com"
|
||||
# DRY_RUN if set to 1, prints actions without changing AD DNS
|
||||
|
||||
PROG="init_prole_dns"
|
||||
STATE_DIR="/var/lib/${PROG}"
|
||||
STATE_FILE="${STATE_DIR}/state.env"
|
||||
CRON_FILE="/etc/cron.d/${PROG}"
|
||||
CONF_DIR="/etc/prole-dns-sync"
|
||||
HOSTS_FILE="${CONF_DIR}/hosts.txt"
|
||||
LOG_TAG="${PROG}"
|
||||
|
||||
AD_DNS_ZONE="${AD_DNS_ZONE:-prole.org}"
|
||||
DRY_RUN="${DRY_RUN:-0}"
|
||||
|
||||
DEFAULT_DB_ENDPOINT="localhost:5432/prole-db"
|
||||
DB_ENDPOINT="$DEFAULT_DB_ENDPOINT"
|
||||
|
||||
mkdir -p "$STATE_DIR" "$CONF_DIR"
|
||||
chmod 700 "$STATE_DIR"
|
||||
|
||||
log() {
|
||||
local msg="$*"
|
||||
logger -t "$LOG_TAG" -- "$msg" 2>/dev/null || true
|
||||
echo "$msg"
|
||||
}
|
||||
|
||||
die() {
|
||||
log "ERROR: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
need_root() {
|
||||
[[ "${EUID:-$(id -u)}" -eq 0 ]] || die "Must run as root."
|
||||
}
|
||||
|
||||
have_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
detect_dc_fqdn() {
|
||||
local fqdn
|
||||
fqdn="$(hostname -f 2>/dev/null || true)"
|
||||
[[ -n "$fqdn" ]] || die "Unable to detect DC FQDN (hostname -f failed)."
|
||||
echo "$fqdn"
|
||||
}
|
||||
|
||||
detect_dc_ip() {
|
||||
local dc_fqdn="$1"
|
||||
local ip
|
||||
ip="$(getent ahostsv4 "$dc_fqdn" 2>/dev/null | awk '{print $1; exit}' || true)"
|
||||
[[ -n "$ip" ]] || die "Unable to detect DC IP for $dc_fqdn (getent ahostsv4 failed)."
|
||||
echo "$ip"
|
||||
}
|
||||
|
||||
detect_public_dns_server() {
|
||||
local ns=""
|
||||
if have_cmd dig; then
|
||||
ns="$(dig +short NS "${AD_DNS_ZONE}" 2>/dev/null | head -n1 | sed 's/\.$//' || true)"
|
||||
fi
|
||||
[[ -n "$ns" ]] || ns="ns1.name.com"
|
||||
echo "$ns"
|
||||
}
|
||||
|
||||
# Parse DB endpoint of form host:port/dbname
|
||||
parse_db_endpoint() {
|
||||
local ep="$1"
|
||||
local hostport="${ep%%/*}"
|
||||
local dbname="${ep#*/}"
|
||||
local host="${hostport%%:*}"
|
||||
local port="${hostport#*:}"
|
||||
|
||||
if [[ "$hostport" == "$host" ]]; then
|
||||
# no port specified
|
||||
port="5432"
|
||||
fi
|
||||
[[ -n "$host" && -n "$port" && -n "$dbname" ]] || return 1
|
||||
|
||||
echo "$host|$port|$dbname"
|
||||
}
|
||||
|
||||
psql_can_connect() {
|
||||
have_cmd psql || return 1
|
||||
local parsed
|
||||
parsed="$(parse_db_endpoint "$DB_ENDPOINT")" || return 1
|
||||
local host="${parsed%%|*}"; parsed="${parsed#*|}"
|
||||
local port="${parsed%%|*}"; local db="${parsed##*|}"
|
||||
|
||||
# Allow interactive password prompting if needed:
|
||||
# We DO NOT add -w (never prompt). We add a short statement timeout.
|
||||
# If auth requires a password and none is cached, this command will prompt.
|
||||
psql -h "$host" -p "$port" -d "$db" -v ON_ERROR_STOP=1 -At \
|
||||
-c "SET statement_timeout='5s'; SELECT 1;" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Functions to check if a string is an IP address
|
||||
is_ipv4() {
|
||||
[[ $1 =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]
|
||||
}
|
||||
|
||||
is_ipv6() {
|
||||
[[ $1 == *:* ]]
|
||||
}
|
||||
|
||||
is_ip() {
|
||||
is_ipv4 "$1" || is_ipv6 "$1"
|
||||
}
|
||||
|
||||
read_hosts_file() {
|
||||
[[ -f "$HOSTS_FILE" ]] || die "Missing $HOSTS_FILE and DB not available. Create it with: hostname [TAB/SPACE] ip_or_target"
|
||||
grep -vE '^\s*($|#)' "$HOSTS_FILE" | awk '{print $1 "|" $2}' || true
|
||||
}
|
||||
|
||||
read_hosts_db() {
|
||||
local parsed
|
||||
parsed="$(parse_db_endpoint "$DB_ENDPOINT")" || die "Invalid -db endpoint '$DB_ENDPOINT' (expected host:port/dbname)"
|
||||
local host="${parsed%%|*}"; parsed="${parsed#*|}"
|
||||
local port="${parsed%%|*}"; local db="${parsed##*|}"
|
||||
|
||||
# This will prompt for password if required by libpq/pg_hba.
|
||||
# Output format: host_name|ip_address
|
||||
psql -h "$host" -p "$port" -d "$db" -v ON_ERROR_STOP=1 -At -F '|' \
|
||||
-c "SELECT host_name, ip_address FROM prole.hosts ORDER BY host_name;"
|
||||
}
|
||||
|
||||
normalize_host() {
|
||||
local raw="$1"
|
||||
raw="${raw%%#*}"
|
||||
# Trim whitespace
|
||||
raw="$(echo "$raw" | xargs)"
|
||||
[[ -n "$raw" ]] || return 1
|
||||
|
||||
local fqdn="$raw"
|
||||
# If it's a short name, append the zone
|
||||
if [[ "$raw" != *.* ]]; then
|
||||
fqdn="${raw}.${AD_DNS_ZONE}"
|
||||
fi
|
||||
|
||||
# Validate it's within our zone
|
||||
if [[ "$fqdn" != *".${AD_DNS_ZONE}" && "$fqdn" != "${AD_DNS_ZONE}" ]]; then
|
||||
# We might be reading a line that has two columns, but normalize_host is called with only the first.
|
||||
# If the user provided a FQDN outside the zone, it's an error for an A/CNAME record name in this script's context.
|
||||
die "Host '$raw' is not within zone '${AD_DNS_ZONE}' (got fqdn '$fqdn')."
|
||||
fi
|
||||
|
||||
local rel="${fqdn%.$AD_DNS_ZONE}"
|
||||
rel="${rel%.}"
|
||||
|
||||
echo "$rel|$fqdn"
|
||||
}
|
||||
|
||||
dig_records() {
|
||||
local dns_server="$1"
|
||||
local fqdn="$2"
|
||||
local a_records aaaa_records
|
||||
|
||||
a_records="$(dig +short @"$dns_server" A "$fqdn" 2>/dev/null | tr '\n' ' ' | xargs || true)"
|
||||
aaaa_records="$(dig +short @"$dns_server" AAAA "$fqdn" 2>/dev/null | tr '\n' ' ' | xargs || true)"
|
||||
echo "$a_records|$aaaa_records"
|
||||
}
|
||||
|
||||
samba_query_rr() {
|
||||
local dc="$1" zone="$2" name="$3" rrtype="$4"
|
||||
samba-tool dns query "$dc" "$zone" "$name" "$rrtype" 2>/dev/null \
|
||||
| awk '
|
||||
BEGIN{inrec=0}
|
||||
/Records:/ {inrec=1; next}
|
||||
inrec && NF>=1 { print $0 }
|
||||
' \
|
||||
| tr '\n' ' ' | xargs || true
|
||||
}
|
||||
|
||||
samba_add_rr() {
|
||||
local dc="$1" zone="$2" name="$3" rrtype="$4" value="$5"
|
||||
if [[ "$DRY_RUN" == "1" ]]; then
|
||||
log "[DRY_RUN] samba-tool dns add $dc $zone $name $rrtype $value"
|
||||
return 0
|
||||
fi
|
||||
samba-tool dns add "$dc" "$zone" "$name" "$rrtype" "$value"
|
||||
}
|
||||
|
||||
samba_update_rr() {
|
||||
local dc="$1" zone="$2" name="$3" rrtype="$4" old="$5" new="$6"
|
||||
if [[ "$DRY_RUN" == "1" ]]; then
|
||||
log "[DRY_RUN] samba-tool dns update $dc $zone $name $rrtype $old $new"
|
||||
return 0
|
||||
fi
|
||||
samba-tool dns update "$dc" "$zone" "$name" "$rrtype" "$old" "$new"
|
||||
}
|
||||
|
||||
sync_rr_set() {
|
||||
local dc="$1" zone="$2" name_rel="$3" fqdn="$4" rrtype="$5" desired_values="$6"
|
||||
[[ -n "$desired_values" ]] || return 0
|
||||
|
||||
local existing
|
||||
existing="$(samba_query_rr "$dc" "$zone" "$name_rel" "$rrtype")"
|
||||
|
||||
for val in $desired_values; do
|
||||
if [[ " $existing " == *" $val "* ]]; then
|
||||
log "OK: $fqdn $rrtype already has $val"
|
||||
else
|
||||
local first_old
|
||||
first_old="$(echo "$existing" | awk '{print $1}' || true)"
|
||||
if [[ -n "$first_old" ]]; then
|
||||
log "UPDATE: $fqdn $rrtype $first_old -> $val"
|
||||
samba_update_rr "$dc" "$zone" "$name_rel" "$rrtype" "$first_old" "$val" || samba_add_rr "$dc" "$zone" "$name_rel" "$rrtype" "$val"
|
||||
else
|
||||
log "ADD: $fqdn $rrtype $val"
|
||||
samba_add_rr "$dc" "$zone" "$name_rel" "$rrtype" "$val"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
write_state() {
|
||||
local key="$1" val="$2"
|
||||
if [[ -f "$STATE_FILE" ]] && grep -qE "^${key}=" "$STATE_FILE"; then
|
||||
sed -i "s|^${key}=.*|${key}=${val}|g" "$STATE_FILE"
|
||||
else
|
||||
echo "${key}=${val}" >> "$STATE_FILE"
|
||||
fi
|
||||
chmod 600 "$STATE_FILE"
|
||||
}
|
||||
|
||||
load_state() {
|
||||
[[ -f "$STATE_FILE" ]] && source "$STATE_FILE" || true
|
||||
}
|
||||
|
||||
install_cron() {
|
||||
local script_path
|
||||
script_path="$(readlink -f "$0")"
|
||||
cat > "$CRON_FILE" <<EOF
|
||||
# Managed by $PROG. Runs hourly.
|
||||
SHELL=/bin/bash
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
0 * * * * root $script_path -db=$DB_ENDPOINT sync >/dev/null 2>&1
|
||||
EOF
|
||||
chmod 644 "$CRON_FILE"
|
||||
log "Installed hourly cron job at $CRON_FILE"
|
||||
}
|
||||
|
||||
remove_cron() {
|
||||
if [[ -f "$CRON_FILE" ]]; then
|
||||
rm -f "$CRON_FILE"
|
||||
log "Removed cron job $CRON_FILE"
|
||||
else
|
||||
log "Cron job not present ($CRON_FILE)"
|
||||
fi
|
||||
}
|
||||
|
||||
choose_host_source() {
|
||||
# Echo "db" if we can connect; otherwise "file"
|
||||
if have_cmd psql; then
|
||||
# We want to allow interactive prompting; connectivity test here should not block forever.
|
||||
# We'll do a *non-interactive* quick check first: if it fails, fall back to file.
|
||||
# (If you want forced DB prompting, run: sudo PSQL_FORCE_PROMPT=1 ... sync)
|
||||
if psql_can_connect; then
|
||||
echo "db"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
echo "file"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
local dc_fqdn dc_ip public_dns source
|
||||
dc_fqdn="${AD_DNS_SERVER:-$(detect_dc_fqdn)}"
|
||||
dc_ip="${AD_DNS_SERVER_IP:-$(detect_dc_ip "$dc_fqdn")}"
|
||||
public_dns="${PUBLIC_DNS_SERVER:-$(detect_public_dns_server)}"
|
||||
source="$(choose_host_source)"
|
||||
|
||||
echo "AD zone : $AD_DNS_ZONE"
|
||||
echo "AD DC (server) : $dc_fqdn"
|
||||
echo "AD DC IP : $dc_ip"
|
||||
echo "Public resolver: $public_dns"
|
||||
echo "DB endpoint : $DB_ENDPOINT"
|
||||
echo "Hosts file : $HOSTS_FILE"
|
||||
echo "Host source : $source"
|
||||
echo
|
||||
|
||||
echo "Hostnames:"
|
||||
if [[ "$source" == "db" ]]; then
|
||||
read_hosts_db | while IFS='|' read -r host ip; do
|
||||
[[ -n "${host// }" ]] || continue
|
||||
local norm rel fqdn
|
||||
norm="$(normalize_host "$host")" || continue
|
||||
rel="${norm%%|*}"
|
||||
fqdn="${norm##*|}"
|
||||
if [[ -n "${ip// }" ]]; then
|
||||
if is_ip "$ip"; then
|
||||
echo " - $fqdn (name='$rel', ip=$ip)"
|
||||
else
|
||||
echo " - $fqdn (name='$rel', cname=$ip)"
|
||||
fi
|
||||
else
|
||||
echo " - $fqdn (name='$rel', ip=<lookup>)"
|
||||
fi
|
||||
done
|
||||
else
|
||||
read_hosts_file | while IFS='|' read -r host ip; do
|
||||
[[ -n "${host// }" ]] || continue
|
||||
local norm rel fqdn
|
||||
norm="$(normalize_host "$host")" || continue
|
||||
rel="${norm%%|*}"
|
||||
fqdn="${norm##*|}"
|
||||
if [[ -n "${ip// }" ]]; then
|
||||
if is_ip "$ip"; then
|
||||
echo " - $fqdn (name='$rel', ip=$ip)"
|
||||
else
|
||||
echo " - $fqdn (name='$rel', cname=$ip)"
|
||||
fi
|
||||
else
|
||||
echo " - $fqdn (name='$rel', ip=<lookup>)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
need_root
|
||||
cmd_sync
|
||||
install_cron
|
||||
}
|
||||
|
||||
cmd_stop() {
|
||||
need_root
|
||||
remove_cron
|
||||
}
|
||||
|
||||
cmd_flush() {
|
||||
need_root
|
||||
rm -f "$STATE_FILE"
|
||||
log "Cleared local state ($STATE_FILE). DNS records were NOT changed."
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
load_state
|
||||
echo "State file: $STATE_FILE"
|
||||
echo " last_run_epoch : ${LAST_RUN_EPOCH:-<unknown>}"
|
||||
if [[ -n "${LAST_RUN_EPOCH:-}" ]]; then
|
||||
date -d "@${LAST_RUN_EPOCH}" +" last_run_time : %F %T %Z"
|
||||
else
|
||||
echo " last_run_time : <unknown>"
|
||||
fi
|
||||
echo " last_exit : ${LAST_EXIT:-<unknown>}"
|
||||
echo " last_source : ${LAST_SOURCE:-<unknown>}"
|
||||
echo " last_public_ns : ${LAST_PUBLIC_DNS:-<unknown>}"
|
||||
echo " last_dc : ${LAST_DC:-<unknown>}"
|
||||
echo " db_endpoint : ${DB_ENDPOINT}"
|
||||
echo
|
||||
echo "Recent logs:"
|
||||
echo "----------------------------------------"
|
||||
journalctl -t "$LOG_TAG" -n 50 --no-pager 2>/dev/null || \
|
||||
echo "(journalctl tag '$LOG_TAG' not available; try: sudo journalctl -n 50 | grep $LOG_TAG)"
|
||||
}
|
||||
|
||||
cmd_sync() {
|
||||
need_root
|
||||
have_cmd samba-tool || die "samba-tool not found (run this on the Samba AD DC)."
|
||||
have_cmd dig || die "dig not found. Install bind9-dnsutils or dnsutils."
|
||||
|
||||
local dc_fqdn dc_ip public_dns source
|
||||
dc_fqdn="${AD_DNS_SERVER:-$(detect_dc_fqdn)}"
|
||||
dc_ip="${AD_DNS_SERVER_IP:-$(detect_dc_ip "$dc_fqdn")}"
|
||||
public_dns="${PUBLIC_DNS_SERVER:-$(detect_public_dns_server)}"
|
||||
source="$(choose_host_source)"
|
||||
|
||||
write_state "LAST_RUN_EPOCH" "$(date +%s)"
|
||||
write_state "LAST_PUBLIC_DNS" "$public_dns"
|
||||
write_state "LAST_DC" "$dc_fqdn"
|
||||
write_state "LAST_SOURCE" "$source"
|
||||
|
||||
log "Starting sync: zone=${AD_DNS_ZONE}, dc=${dc_fqdn} (${dc_ip}), public_dns=${public_dns}, source=${source}, db=${DB_ENDPOINT}, dry_run=${DRY_RUN}"
|
||||
|
||||
local exit_code=0
|
||||
|
||||
# Helper to process a single host entry
|
||||
process_host() {
|
||||
local host="$1" ip="$2"
|
||||
[[ -n "${host// }" ]] || return 0
|
||||
local norm rel fqdn
|
||||
norm="$(normalize_host "$host")" || return 0
|
||||
rel="${norm%%|*}"
|
||||
fqdn="${norm##*|}"
|
||||
|
||||
# Skip zone apex
|
||||
if [[ "$fqdn" == "$AD_DNS_ZONE" ]]; then
|
||||
log "INFO: Skipping zone apex $fqdn"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local a_vals="" aaaa_vals="" cname_vals=""
|
||||
if [[ -n "${ip// }" ]]; then
|
||||
if is_ip "$ip"; then
|
||||
# If a single IP is provided, classify as v4/v6
|
||||
if is_ipv6 "$ip"; then
|
||||
aaaa_vals="$ip"
|
||||
else
|
||||
a_vals="$ip"
|
||||
fi
|
||||
else
|
||||
# It's a hostname, use CNAME
|
||||
cname_vals="$ip"
|
||||
fi
|
||||
else
|
||||
# No IP in entry: resolve from public DNS
|
||||
local recs
|
||||
recs="$(dig_records "$public_dns" "$fqdn")"
|
||||
a_vals="${recs%%|*}"
|
||||
aaaa_vals="${recs##*|}"
|
||||
if [[ -z "$a_vals" && -z "$aaaa_vals" ]]; then
|
||||
log "WARN: No A/AAAA in public DNS for $fqdn (via $public_dns); skipping"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local ret=0
|
||||
if [[ -n "$a_vals" ]]; then
|
||||
if ! sync_rr_set "$dc_fqdn" "$AD_DNS_ZONE" "$rel" "$fqdn" "A" "$a_vals"; then ret=1; fi
|
||||
fi
|
||||
if [[ -n "$aaaa_vals" ]]; then
|
||||
if ! sync_rr_set "$dc_fqdn" "$AD_DNS_ZONE" "$rel" "$fqdn" "AAAA" "$aaaa_vals"; then ret=1; fi
|
||||
fi
|
||||
if [[ -n "$cname_vals" ]]; then
|
||||
# Samba-tool CNAME values should ideally be FQDN with trailing dot for safety,
|
||||
# but let's see how it handles it. The issue says "samba-tool dns add .. cname"
|
||||
if ! sync_rr_set "$dc_fqdn" "$AD_DNS_ZONE" "$rel" "$fqdn" "CNAME" "$cname_vals"; then ret=1; fi
|
||||
fi
|
||||
return $ret
|
||||
}
|
||||
|
||||
if [[ "$source" == "db" ]]; then
|
||||
while IFS='|' read -r host ip; do
|
||||
if ! process_host "$host" "$ip"; then exit_code=1; fi
|
||||
done < <(read_hosts_db)
|
||||
else
|
||||
while IFS='|' read -r host ip; do
|
||||
if ! process_host "$host" "$ip"; then exit_code=1; fi
|
||||
done < <(read_hosts_file)
|
||||
fi
|
||||
|
||||
write_state "LAST_EXIT" "$exit_code"
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
log "Sync complete: success"
|
||||
else
|
||||
log "Sync complete: errors occurred"
|
||||
fi
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [-db=host:port/dbname] <command>
|
||||
|
||||
Commands:
|
||||
start Run sync now and install hourly cron job
|
||||
stop Remove hourly cron job
|
||||
status Show last run time, exit status, and recent logs
|
||||
sync Run one sync pass now
|
||||
flush Clear local state file (does not change DNS records)
|
||||
list Show host list + DC info (alias: show, details)
|
||||
show Alias for list
|
||||
details Alias for list
|
||||
|
||||
DB option:
|
||||
-db=HOST:PORT/DBNAME default: ${DEFAULT_DB_ENDPOINT}
|
||||
|
||||
Host list sources:
|
||||
1) If psql exists and DB is reachable:
|
||||
SELECT host_name, ip_address FROM prole.hosts;
|
||||
(psql may prompt for password interactively)
|
||||
2) Else: $HOSTS_FILE
|
||||
|
||||
Examples:
|
||||
sudo $0 sync
|
||||
sudo $0 -db=localhost:5432/prole-db sync
|
||||
sudo DRY_RUN=1 $0 sync
|
||||
sudo $0 start
|
||||
sudo $0 status
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
# Parse -db=... and keep remaining args
|
||||
local args=()
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
-db=*) DB_ENDPOINT="${a#-db=}" ;;
|
||||
*) args+=("$a") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
local cmd="${args[0]:-}"
|
||||
case "$cmd" in
|
||||
start) cmd_start ;;
|
||||
stop) cmd_stop ;;
|
||||
status) cmd_status ;;
|
||||
sync) cmd_sync ;;
|
||||
flush) cmd_flush ;;
|
||||
list|show|details) cmd_list ;;
|
||||
""|-h|--help|help) usage ;;
|
||||
*) die "Unknown command: $cmd (try --help)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Loading…
Reference in New Issue
Block a user