Merakit-Deploy/scripts/cloudflare-add.sh

230 lines
5.4 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# Cloudflare API credentials
CF_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}"
CF_ZONE_ID="${CLOUDFLARE_ZONE_ID:-}"
# Dictionary files
DICT_FILE="/usr/share/dict/words"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
usage() {
echo "Usage: $0 --hostname <hostname> --ip <ip_address>"
echo " $0 --random --domain <domain> --ip <ip_address>"
echo ""
echo "Options:"
echo " --hostname Specific hostname to add (e.g., test.example.com)"
echo " --random Generate random hostname"
echo " --domain Base domain for random hostname (e.g., example.org)"
echo " --ip IP address for A record"
echo ""
echo "Environment variables required:"
echo " CLOUDFLARE_API_TOKEN"
echo " CLOUDFLARE_ZONE_ID"
exit 1
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1" >&2
}
log_info() {
echo -e "${YELLOW}[INFO]${NC} $1" >&2
}
check_requirements() {
if [[ -z "$CF_API_TOKEN" ]]; then
log_error "CLOUDFLARE_API_TOKEN environment variable not set"
exit 1
fi
if [[ -z "$CF_ZONE_ID" ]]; then
log_error "CLOUDFLARE_ZONE_ID environment variable not set"
exit 1
fi
if ! command -v curl &> /dev/null; then
log_error "curl is required but not installed"
exit 1
fi
if ! command -v jq &> /dev/null; then
log_error "jq is required but not installed"
exit 1
fi
}
get_random_word() {
if [[ ! -f "$DICT_FILE" ]]; then
log_error "Dictionary file not found: $DICT_FILE"
exit 1
fi
# Get random word: lowercase, letters only, 3-10 characters
grep -E '^[a-z]{3,10}$' "$DICT_FILE" | shuf -n 1
}
generate_random_hostname() {
local domain=$1
local word1=$(get_random_word)
local word2=$(get_random_word)
echo "${word1}-${word2}.${domain}"
}
check_dns_exists() {
local hostname=$1
log_info "Checking if DNS record exists for: $hostname"
local response=$(curl -s -X GET \
"https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records?name=${hostname}" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json")
local success=$(echo "$response" | jq -r '.success')
if [[ "$success" != "true" ]]; then
log_error "Cloudflare API request failed"
echo "$response" | jq '.'
exit 1
fi
local count=$(echo "$response" | jq -r '.result | length')
if [[ "$count" -gt 0 ]]; then
return 0 # Record exists
else
return 1 # Record does not exist
fi
}
add_dns_record() {
local hostname=$1
local ip=$2
log_info "Adding DNS record: $hostname -> $ip"
local response=$(curl -s -X POST \
"https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"A\",
\"name\": \"${hostname}\",
\"content\": \"${ip}\",
\"ttl\": 1,
\"proxied\": false
}")
local success=$(echo "$response" | jq -r '.success')
if [[ "$success" == "true" ]]; then
log_success "DNS record added successfully: $hostname -> $ip"
echo "$response" | jq -r '.result | "Record ID: \(.id)"'
return 0
else
log_error "Failed to add DNS record"
echo "$response" | jq '.'
return 1
fi
}
# Parse arguments
HOSTNAME=""
IP=""
RANDOM_MODE=false
DOMAIN=""
while [[ $# -gt 0 ]]; do
case $1 in
--hostname)
HOSTNAME="$2"
shift 2
;;
--ip)
IP="$2"
shift 2
;;
--random)
RANDOM_MODE=true
shift
;;
--domain)
DOMAIN="$2"
shift 2
;;
-h|--help)
usage
;;
*)
log_error "Unknown option: $1"
usage
;;
esac
done
# Validate arguments
if [[ -z "$IP" ]]; then
log_error "IP address is required"
usage
fi
if [[ "$RANDOM_MODE" == true ]]; then
if [[ -z "$DOMAIN" ]]; then
log_error "Domain is required when using --random mode"
usage
fi
else
if [[ -z "$HOSTNAME" ]]; then
log_error "Hostname is required"
usage
fi
fi
# Check requirements
check_requirements
# Generate or use provided hostname
if [[ "$RANDOM_MODE" == true ]]; then
MAX_ATTEMPTS=50
attempt=1
while [[ $attempt -le $MAX_ATTEMPTS ]]; do
HOSTNAME=$(generate_random_hostname "$DOMAIN")
log_info "Generated hostname (attempt $attempt): $HOSTNAME"
if ! check_dns_exists "$HOSTNAME"; then
log_success "Hostname is available: $HOSTNAME"
break
else
log_info "Hostname already exists, generating new one..."
attempt=$((attempt + 1))
fi
done
if [[ $attempt -gt $MAX_ATTEMPTS ]]; then
log_error "Failed to generate unique hostname after $MAX_ATTEMPTS attempts"
exit 1
fi
else
if check_dns_exists "$HOSTNAME"; then
log_error "DNS record already exists for: $HOSTNAME"
exit 1
fi
fi
# Add the DNS record
add_dns_record "$HOSTNAME" "$IP"