checkpoint commit
All checks were successful
Podman DDNS Image / build-and-push-ddns (push) Successful in 1m3s
All checks were successful
Podman DDNS Image / build-and-push-ddns (push) Successful in 1m3s
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
76
active/aws_route53/sync_unifi_records.sh
Executable file
76
active/aws_route53/sync_unifi_records.sh
Executable 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}"
|
||||
113
active/aws_route53/unifi_to_aws.py
Normal file
113
active/aws_route53/unifi_to_aws.py
Normal 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()
|
||||
Reference in New Issue
Block a user