checkpoint commit
All checks were successful
Podman DDNS Image / build-and-push-ddns (push) Successful in 1m3s

This commit is contained in:
2026-05-05 06:26:40 -04:00
parent e43c534ceb
commit f2015e2c71
76 changed files with 4265 additions and 235 deletions

View File

@@ -4,6 +4,7 @@
- [Reeseapps vs Reeselink](#reeseapps-vs-reeselink)
- [Reeselink Addresses](#reeselink-addresses)
- [Reeseapps Addresses](#reeseapps-addresses)
- [Converting Unifi Records to AWS Records](#converting-unifi-records-to-aws-records)
## Reeseapps vs Reeselink
@@ -28,3 +29,14 @@ aws route53 change-resource-record-sets --hosted-zone-id $(cat active/aws_route5
```bash
aws route53 change-resource-record-sets --hosted-zone-id $(cat active/aws_route53/secrets/reeseapps-zoneid) --change-batch file://active/aws_route53/secrets/reeseapps.json
```
## Converting Unifi Records to AWS Records
The script `unifi_to_aws.py` will create a file at
`secrets/unifi_reeselink_records.json` which contains all `reeselink.com`
domains in the unifi server converted to AWS route53 batch format. Simply run
the script and then use that file to update reeselink.com records.
```python
python active/aws_route53/unifi_to_aws.py
```

View File

@@ -0,0 +1,76 @@
#!/bin/bash
# --- Configuration ---
PYTHON_SCRIPT="active/aws_route53/unifi_to_aws.py"
ZONE_ID_FILE="active/aws_route53/secrets/reeselink-zoneid"
RECORDS_FILE="active/aws_route53/secrets/unifi_reeselink_records.json"
# --- Colors for logging ---
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# --- Logging Function ---
log() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
error_exit() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] ${RED}ERROR: $1${NC}" >&2
exit 1
}
# --- 1. Pre-flight Checks ---
log "${YELLOW}Starting Route53 update process...${NC}"
if [[ ! -f "$PYTHON_SCRIPT" ]]; then
error_exit "Python script not found at $PYTHON_SCRIPT"
fi
if [[ ! -f "$ZONE_ID_FILE" ]]; then
error_exit "Zone ID file not found at $ZONE_ID_FILE"
fi
# --- 2. Run Python Script ---
log "Running $PYTHON_SCRIPT to generate JSON records..."
# Execute the python script
python "$PYTHON_SCRIPT"
# Check the exit code of the python script
if [[ $? -eq 0 ]]; then
log "${GREEN}Python script executed successfully.${NC}"
else
error_exit "Python script failed. Aborting AWS update to prevent corrupting DNS."
fi
# Verify the output file actually exists after the python run
if [[ ! -f "$RECORDS_FILE" ]]; then
error_exit "Python script reported success, but $RECORDS_FILE was not found."
fi
# --- 3. Update Route53 ---
# Read the Zone ID from the secret file
ZONE_ID=$(cat "$ZONE_ID_FILE" | tr -d '\n\r ')
if [[ -z "$ZONE_ID" ]]; then
error_exit "Zone ID file is empty or could not be read."
fi
log "Updating Route53 records for Zone ID: $ZONE_ID..."
# Run the AWS CLI command
# Using file:// prefix as required by AWS CLI for local files
aws route53 change-resource-record-sets \
--hosted-zone-id "$ZONE_ID" \
--change-batch "file://$RECORDS_FILE"
# Check the exit code of the AWS command
if [[ $? -eq 0 ]]; then
log "${GREEN}Route53 records updated successfully!${NC}"
else
error_exit "AWS CLI command failed. Check your AWS credentials and JSON formatting."
fi
log "${GREEN}Process complete.${NC}"

View File

@@ -0,0 +1,113 @@
import json
import os
import sys
from typing import Any, Dict, List
import requests
# Configuration
API_KEY = os.environ.get("API_KEY")
URL_DEVICES = "https://10.1.0.1/proxy/network/v2/api/site/default/static-dns/devices"
URL_POLICIES = "https://10.1.0.1/proxy/network/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies"
OUTPUT_FILE = "active/aws_route53/secrets/unifi_reeselink_records.json"
ALLOWED_DOMAIN = "reeselink.com"
FIXED_TTL = 60
# Headers
headers = {"Accept": "application/json", "X-API-Key": API_KEY}
def fetch_json(url: str) -> Any:
"""Helper to perform the GET request and return parsed JSON."""
response = requests.get(
url,
headers=headers,
verify=False, # -k: Don't verify SSL certificate
allow_redirects=True, # -L: Follow redirects
)
if response.status_code != 200:
print(f"Error: Received status code {response.status_code} from {url}")
print(f"Response: {response.text}")
sys.exit(1)
return response.json()
def main():
all_changes: List[Dict[str, Any]] = []
# 1. Process Devices API
devices_data = fetch_json(URL_DEVICES)
devices_count = 0
# devices_data is expected to be a list: [{hostname: ..., ip_address: ...}, ...]
for device in devices_data:
hostname = device.get("hostname", "")
ip = device.get("ip_address", "")
if hostname.endswith(ALLOWED_DOMAIN):
all_changes.append(
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": hostname,
"Type": "A",
"TTL": FIXED_TTL,
"ResourceRecords": [{"Value": ip}],
},
}
)
devices_count += 1
# 2. Process Policies API
policies_response = fetch_json(URL_POLICIES)
policies_count = 0
# policies_response is expected to be a dict: {"data": [{domain: ..., ipv4Address: ...}, ...]}
policies_list = policies_response.get("data", [])
for policy in policies_list:
domain = policy.get("domain", "")
ip = policy.get("ipv4Address", "")
if domain.endswith(ALLOWED_DOMAIN):
all_changes.append(
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": domain,
"Type": "A",
"TTL": FIXED_TTL,
"ResourceRecords": [{"Value": ip}],
},
}
)
policies_count += 1
# Construct Final AWS Payload
final_payload = {
"Comment": "Combined records from Unifi devices and policies",
"Changes": all_changes,
}
# Write to file
try:
# Ensure directory exists
os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True)
with open(OUTPUT_FILE, "w") as f:
json.dump(final_payload, f, indent=4)
except Exception as e:
print(f"Error writing to file: {e}")
sys.exit(1)
# Print Summary
print(f"Successfully processed records:")
print(f" - devices: {devices_count}")
print(f" - policies: {policies_count}")
print(f"Total records in file: {len(all_changes)}")
print(f"Saved to {OUTPUT_FILE}")
if __name__ == "__main__":
# Suppress InsecureRequestWarning for verify=False
requests.packages.urllib3.disable_warnings() # type: ignore
main()