mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-18 03:33:59 -05:00
Add domain management system
Implements a declarative domain orchestrator that reads ops/domains.yaml and automatically applies DNS and forwarding configuration via GoDaddy and Cloudflare APIs. Features: - YAML-based configuration for all domains (ops/domains.yaml) - Python script to apply changes idempotently (ops/scripts/apply_domains.py) - GitHub Actions workflow to sync on YAML changes (sync-domains.yml) - Optional health check workflow (domain-health.yml) - Comprehensive documentation (docs/domains-overview.md) The system supports: - GoDaddy: DNS records and 301 forwarding - Cloudflare: DNS records (CNAME, A) All API credentials are read from GitHub secrets (GODADDY_API_KEY, GODADDY_API_SECRET, CLOUDFLARE_TOKEN).
This commit is contained in:
46
.github/workflows/domain-health.yml
vendored
Normal file
46
.github/workflows/domain-health.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: Domain Health Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 */6 * * *" # every 6 hours
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
health:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install pyyaml requests
|
||||||
|
|
||||||
|
- name: Run health checks
|
||||||
|
env:
|
||||||
|
# Add any API keys if needed for your health checks (not required for simple HTTP GET)
|
||||||
|
run: |
|
||||||
|
python - <<'PY'
|
||||||
|
import yaml, requests, os
|
||||||
|
|
||||||
|
with open("ops/domains.yaml") as f:
|
||||||
|
cfg = yaml.safe_load(f)
|
||||||
|
|
||||||
|
for d in cfg.get("domains", []):
|
||||||
|
# Only health-check DNS records pointing to HTTP(S) targets
|
||||||
|
health = d.get("healthcheck", False)
|
||||||
|
if d.get("mode") == "dns" and health:
|
||||||
|
url = "https://" + d["name"]
|
||||||
|
try:
|
||||||
|
r = requests.get(url, timeout=10)
|
||||||
|
status = "healthy" if r.status_code < 400 else f"unhealthy (status {r.status_code})"
|
||||||
|
except Exception as e:
|
||||||
|
status = f"unhealthy (error {e})"
|
||||||
|
print(f"{d['name']}: {status}")
|
||||||
|
PY
|
||||||
34
.github/workflows/sync-domains.yml
vendored
Normal file
34
.github/workflows/sync-domains.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Sync Domains
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: {}
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- ops/domains.yaml
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install pyyaml requests
|
||||||
|
|
||||||
|
- name: Apply domain configuration
|
||||||
|
env:
|
||||||
|
GODADDY_API_KEY: ${{ secrets.GODADDY_API_KEY }}
|
||||||
|
GODADDY_API_SECRET: ${{ secrets.GODADDY_API_SECRET }}
|
||||||
|
CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}
|
||||||
|
# Optionally set CLOUDFLARE_ACCOUNT_ID if needed by your script
|
||||||
|
run: |
|
||||||
|
python ops/scripts/apply_domains.py
|
||||||
63
docs/domains-overview.md
Normal file
63
docs/domains-overview.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Domain Management Overview
|
||||||
|
|
||||||
|
This repository includes a **universal domain orchestrator** that allows you to declare all of your domains in a single YAML file and sync them to your DNS providers automatically. The goal is to avoid manual updates in registrar dashboards by defining a clear desired state and letting automation converge on it.
|
||||||
|
|
||||||
|
## Configuration File (`ops/domains.yaml`)
|
||||||
|
|
||||||
|
The `ops/domains.yaml` file lists each domain or subdomain with the following fields:
|
||||||
|
|
||||||
|
- **name**: The fully qualified domain or subdomain (e.g. `blackroad.systems`, `os.blackroad.systems`).
|
||||||
|
- **type**: `"root"` for an apex domain or `"subdomain"` for a subdomain.
|
||||||
|
- **provider**: Which registrar/DNS provider the domain lives in (`godaddy` or `cloudflare`).
|
||||||
|
- **mode**:
|
||||||
|
- `forward` – perform a 301 (permanent) redirect to another URL.
|
||||||
|
- `dns` – create or update a DNS record (CNAME or A).
|
||||||
|
- **forward_to** (only for `forward`): The destination URL to forward to.
|
||||||
|
- **forwarding_type** (optional): HTTP status code for forwarding (301 by default).
|
||||||
|
- **record** (only for `dns`): A mapping with `type` (`CNAME` or `A`) and `value` (target hostname or IP).
|
||||||
|
- **healthcheck** (optional): Set to `true` to enable periodic health checks in the optional workflow.
|
||||||
|
|
||||||
|
Add as many entries as needed; the script processes them sequentially.
|
||||||
|
|
||||||
|
## Domain Sync Script (`ops/scripts/apply_domains.py`)
|
||||||
|
|
||||||
|
This Python script:
|
||||||
|
|
||||||
|
1. Parses `ops/domains.yaml`.
|
||||||
|
2. For GoDaddy domains:
|
||||||
|
- Uses the GoDaddy API to set forwarding rules or DNS records.
|
||||||
|
- A permanent 301 redirect tells search engines to treat the destination as the canonical URL.
|
||||||
|
3. For Cloudflare domains:
|
||||||
|
- Finds the zone ID for the root domain.
|
||||||
|
- Creates or updates DNS records using the Cloudflare API, which supports PUT/PATCH requests to overwrite DNS entries.
|
||||||
|
4. Prints a summary of actions taken; if nothing changed, it reports that the record is up to date.
|
||||||
|
|
||||||
|
All credentials (GoDaddy key/secret and Cloudflare token) are read from environment variables. **Never hard‑code secrets.** Set them as GitHub repository secrets (Settings → Secrets and variables → Actions).
|
||||||
|
|
||||||
|
## GitHub Actions Workflows
|
||||||
|
|
||||||
|
### `sync-domains.yml`
|
||||||
|
|
||||||
|
- Runs on pushes to `main` where `ops/domains.yaml` changes, or via manual trigger.
|
||||||
|
- Checks out the repo, installs Python dependencies, and runs the sync script.
|
||||||
|
- Uses secrets to authenticate to GoDaddy and Cloudflare.
|
||||||
|
- Annotates logs with changes so you can see which domains were updated.
|
||||||
|
|
||||||
|
### `domain-health.yml` (optional)
|
||||||
|
|
||||||
|
- Runs every six hours (or manually).
|
||||||
|
- Reads `ops/domains.yaml` and performs an HTTP GET against any domain marked `healthcheck: true`.
|
||||||
|
- Logs whether the domain is reachable; you can extend it to open GitHub Issues on repeated failures.
|
||||||
|
|
||||||
|
## How To Add or Modify Domains
|
||||||
|
|
||||||
|
1. Open `ops/domains.yaml` and add a new entry for each domain or subdomain you own.
|
||||||
|
2. Specify its `provider`, `mode`, and either `forward_to` or a DNS `record`.
|
||||||
|
3. Commit and push your changes to `main`.
|
||||||
|
4. Ensure the following secrets are configured in GitHub:
|
||||||
|
- `GODADDY_API_KEY`, `GODADDY_API_SECRET`
|
||||||
|
- `CLOUDFLARE_TOKEN`
|
||||||
|
5. Run the **Sync Domains** workflow manually (Actions → Sync Domains → Run workflow) or wait for the push trigger.
|
||||||
|
6. Verify your DNS or forwarding settings with `dig` or by visiting the domains.
|
||||||
|
|
||||||
|
By following this process, you maintain a single source of truth for all of your domains and eliminate the need to log into registrar dashboards for each change.
|
||||||
57
ops/domains.yaml
Normal file
57
ops/domains.yaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Universal domain registry configuration
|
||||||
|
# Each entry describes how a domain or subdomain should be handled.
|
||||||
|
# Supported providers: "godaddy", "cloudflare"
|
||||||
|
# Supported modes:
|
||||||
|
# - forward: use registrar forwarding (HTTPS 301)
|
||||||
|
# - dns: set DNS records (CNAME or A)
|
||||||
|
|
||||||
|
domains:
|
||||||
|
- name: "blackroad.systems"
|
||||||
|
type: "root"
|
||||||
|
provider: "godaddy"
|
||||||
|
mode: "forward"
|
||||||
|
forward_to: "https://os.blackroad.systems"
|
||||||
|
forwarding_type: 301
|
||||||
|
|
||||||
|
- name: "www.blackroad.systems"
|
||||||
|
type: "subdomain"
|
||||||
|
provider: "godaddy"
|
||||||
|
mode: "forward"
|
||||||
|
forward_to: "https://os.blackroad.systems"
|
||||||
|
forwarding_type: 301
|
||||||
|
|
||||||
|
- name: "os.blackroad.systems"
|
||||||
|
type: "subdomain"
|
||||||
|
provider: "godaddy"
|
||||||
|
mode: "dns"
|
||||||
|
record:
|
||||||
|
type: "CNAME"
|
||||||
|
value: "YOUR-PROD-RAILWAY-APP.up.railway.app" # replace with your Railway host
|
||||||
|
|
||||||
|
- name: "blackroad.ai"
|
||||||
|
type: "root"
|
||||||
|
provider: "cloudflare"
|
||||||
|
mode: "dns"
|
||||||
|
record:
|
||||||
|
type: "CNAME"
|
||||||
|
value: "os.blackroad.systems"
|
||||||
|
|
||||||
|
- name: "roadwallet.com"
|
||||||
|
type: "root"
|
||||||
|
provider: "cloudflare"
|
||||||
|
mode: "dns"
|
||||||
|
record:
|
||||||
|
type: "CNAME"
|
||||||
|
value: "os.blackroad.systems"
|
||||||
|
|
||||||
|
- name: "aliceos.io"
|
||||||
|
type: "root"
|
||||||
|
provider: "cloudflare"
|
||||||
|
mode: "dns"
|
||||||
|
record:
|
||||||
|
type: "CNAME"
|
||||||
|
value: "os.blackroad.systems"
|
||||||
|
|
||||||
|
# Add additional domains or subdomains here following the same pattern.
|
||||||
|
# By default you can set mode: "dns" with a CNAME pointing to os.blackroad.systems,
|
||||||
|
# or override as needed.
|
||||||
262
ops/scripts/apply_domains.py
Executable file
262
ops/scripts/apply_domains.py
Executable file
@@ -0,0 +1,262 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
apply_domains.py
|
||||||
|
|
||||||
|
Reads ops/domains.yaml and ensures that each domain's DNS/forwarding
|
||||||
|
settings are correctly applied via GoDaddy and Cloudflare APIs.
|
||||||
|
This script is designed to be idempotent: re-running it will not create
|
||||||
|
duplicate records.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- PyYAML (for parsing YAML)
|
||||||
|
- requests (for HTTP calls)
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
GODADDY_API_KEY, GODADDY_API_SECRET -- GoDaddy API credentials
|
||||||
|
CLOUDFLARE_TOKEN -- Cloudflare API token with DNS write permission
|
||||||
|
CLOUDFLARE_ACCOUNT_ID (optional) -- Cloudflare account ID if needed
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
import requests
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
CONFIG_PATH = os.path.join("ops", "domains.yaml")
|
||||||
|
|
||||||
|
# Helpers for GoDaddy
|
||||||
|
GODADDY_BASE_URL = "https://api.godaddy.com/v1"
|
||||||
|
|
||||||
|
def godaddy_headers():
|
||||||
|
key = os.getenv("GODADDY_API_KEY")
|
||||||
|
secret = os.getenv("GODADDY_API_SECRET")
|
||||||
|
if not key or not secret:
|
||||||
|
raise EnvironmentError("Missing GoDaddy API credentials. Set GODADDY_API_KEY and GODADDY_API_SECRET.")
|
||||||
|
return {
|
||||||
|
"Authorization": f"sso-key {key}:{secret}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse_domain_name(domain):
|
||||||
|
"""
|
||||||
|
Return (root_domain, subdomain) tuple.
|
||||||
|
For root domains, subdomain is '@'.
|
||||||
|
"""
|
||||||
|
parts = domain.split(".")
|
||||||
|
if len(parts) <= 2:
|
||||||
|
return domain, "@"
|
||||||
|
# e.g. 'os.blackroad.systems' => root 'blackroad.systems', sub 'os'
|
||||||
|
root = ".".join(parts[-2:])
|
||||||
|
sub = ".".join(parts[:-2])
|
||||||
|
return root, sub
|
||||||
|
|
||||||
|
def update_godaddy_forward(domain_entry):
|
||||||
|
"""Apply forwarding for a domain using GoDaddy API."""
|
||||||
|
name = domain_entry["name"]
|
||||||
|
forward_to = domain_entry["forward_to"]
|
||||||
|
status_code = domain_entry.get("forwarding_type", 301)
|
||||||
|
|
||||||
|
root_domain, sub = parse_domain_name(name)
|
||||||
|
url = f"{GODADDY_BASE_URL}/domains/{root_domain}/forwarding"
|
||||||
|
headers = godaddy_headers()
|
||||||
|
|
||||||
|
# Build forwarding payload
|
||||||
|
payload = {"forwarding": {}}
|
||||||
|
if sub == "@":
|
||||||
|
payload["forwarding"]["domain"] = {
|
||||||
|
"forwardTo": forward_to,
|
||||||
|
"redirectType": "permanent" if status_code == 301 else "temporary",
|
||||||
|
"allowSubdomains": True
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
payload["forwarding"]["subdomain"] = [
|
||||||
|
{
|
||||||
|
"subdomain": sub,
|
||||||
|
"forwardTo": forward_to,
|
||||||
|
"redirectType": "permanent" if status_code == 301 else "temporary"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Check existing forwarding settings
|
||||||
|
try:
|
||||||
|
resp = requests.get(url, headers=headers)
|
||||||
|
resp.raise_for_status()
|
||||||
|
current = resp.json()
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Failed to fetch current forwarding for {name}: {e}")
|
||||||
|
current = {}
|
||||||
|
|
||||||
|
def forwarding_needs_update():
|
||||||
|
# Compare desired vs. current
|
||||||
|
if sub == "@":
|
||||||
|
desired = payload["forwarding"].get("domain")
|
||||||
|
current_domain = current.get("domain", {})
|
||||||
|
return not current_domain or current_domain.get("forwardTo") != desired["forwardTo"]
|
||||||
|
else:
|
||||||
|
desired = payload["forwarding"]["subdomain"][0]
|
||||||
|
sub_list = current.get("subdomain", [])
|
||||||
|
for item in sub_list:
|
||||||
|
if item.get("subdomain") == sub and item.get("forwardTo") == desired["forwardTo"]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if forwarding_needs_update():
|
||||||
|
print(f"Updating forwarding for {name} -> {forward_to}")
|
||||||
|
try:
|
||||||
|
resp = requests.put(url, headers=headers, json=payload)
|
||||||
|
resp.raise_for_status()
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error updating forwarding for {name}: {e}")
|
||||||
|
else:
|
||||||
|
print(f"No forwarding changes needed for {name}")
|
||||||
|
|
||||||
|
def update_godaddy_dns_record(domain_entry):
|
||||||
|
"""Ensure DNS record exists for GoDaddy domain."""
|
||||||
|
full_name = domain_entry["name"]
|
||||||
|
record = domain_entry["record"]
|
||||||
|
record_type = record["type"].upper()
|
||||||
|
record_value = record["value"]
|
||||||
|
|
||||||
|
root_domain, sub = parse_domain_name(full_name)
|
||||||
|
headers = godaddy_headers()
|
||||||
|
|
||||||
|
# Get current records
|
||||||
|
get_url = f"{GODADDY_BASE_URL}/domains/{root_domain}/records/{record_type}/{sub}"
|
||||||
|
try:
|
||||||
|
resp = requests.get(get_url, headers=headers)
|
||||||
|
resp.raise_for_status()
|
||||||
|
current_records = resp.json() or []
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error fetching current records for {full_name}: {e}")
|
||||||
|
current_records = []
|
||||||
|
|
||||||
|
current_data = [rec.get("data") for rec in current_records]
|
||||||
|
if record_value in current_data:
|
||||||
|
print(f"{full_name}: DNS record already set to {record_value}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Prepare new record payload
|
||||||
|
payload = [{"data": record_value, "ttl": 600}]
|
||||||
|
put_url = f"{GODADDY_BASE_URL}/domains/{root_domain}/records/{record_type}/{sub}"
|
||||||
|
|
||||||
|
print(f"Updating DNS record for {full_name}: {record_type} -> {record_value}")
|
||||||
|
try:
|
||||||
|
resp = requests.put(put_url, headers=headers, json=payload)
|
||||||
|
resp.raise_for_status()
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error updating DNS record for {full_name}: {e}")
|
||||||
|
|
||||||
|
# Helpers for Cloudflare
|
||||||
|
CLOUDFLARE_API = "https://api.cloudflare.com/client/v4"
|
||||||
|
|
||||||
|
def cf_headers():
|
||||||
|
token = os.getenv("CLOUDFLARE_TOKEN")
|
||||||
|
if not token:
|
||||||
|
raise EnvironmentError("Missing Cloudflare API token. Set CLOUDFLARE_TOKEN.")
|
||||||
|
return {
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_cf_zone_id(root_domain):
|
||||||
|
"""Return zone_id for a domain via Cloudflare API."""
|
||||||
|
params = {"name": root_domain, "status": "active"}
|
||||||
|
try:
|
||||||
|
resp = requests.get(f"{CLOUDFLARE_API}/zones", headers=cf_headers(), params=params)
|
||||||
|
resp.raise_for_status()
|
||||||
|
data = resp.json()
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error retrieving Cloudflare zone for {root_domain}: {e}")
|
||||||
|
return None
|
||||||
|
result = data.get("result", [])
|
||||||
|
if not result:
|
||||||
|
print(f"No active Cloudflare zone found for {root_domain}")
|
||||||
|
return None
|
||||||
|
return result[0]["id"]
|
||||||
|
|
||||||
|
def update_cloudflare_dns_record(domain_entry):
|
||||||
|
"""Create or update a DNS record on Cloudflare."""
|
||||||
|
full_name = domain_entry["name"]
|
||||||
|
record = domain_entry["record"]
|
||||||
|
record_type = record["type"].upper()
|
||||||
|
record_value = record["value"]
|
||||||
|
|
||||||
|
root_domain, sub = parse_domain_name(full_name)
|
||||||
|
zone_id = get_cf_zone_id(root_domain)
|
||||||
|
if not zone_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Determine the record name field expected by CF (full domain)
|
||||||
|
record_name = full_name
|
||||||
|
|
||||||
|
# List existing records to find match
|
||||||
|
try:
|
||||||
|
resp = requests.get(f"{CLOUDFLARE_API}/zones/{zone_id}/dns_records",
|
||||||
|
headers=cf_headers(),
|
||||||
|
params={"type": record_type, "name": record_name})
|
||||||
|
resp.raise_for_status()
|
||||||
|
results = resp.json().get("result", [])
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error listing Cloudflare records for {full_name}: {e}")
|
||||||
|
results = []
|
||||||
|
|
||||||
|
if results:
|
||||||
|
# update existing record if value differs
|
||||||
|
record_id = results[0]["id"]
|
||||||
|
current_value = results[0]["content"]
|
||||||
|
if current_value == record_value:
|
||||||
|
print(f"{full_name}: Cloudflare record already set to {record_value}")
|
||||||
|
return
|
||||||
|
payload = {"type": record_type, "name": record_name, "content": record_value, "ttl": 300, "proxied": False}
|
||||||
|
print(f"Updating Cloudflare record for {full_name}: {record_type} -> {record_value}")
|
||||||
|
try:
|
||||||
|
resp = requests.put(f"{CLOUDFLARE_API}/zones/{zone_id}/dns_records/{record_id}",
|
||||||
|
headers=cf_headers(), json=payload)
|
||||||
|
resp.raise_for_status()
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error updating Cloudflare record for {full_name}: {e}")
|
||||||
|
else:
|
||||||
|
# create new record
|
||||||
|
payload = {"type": record_type, "name": record_name, "content": record_value, "ttl": 300, "proxied": False}
|
||||||
|
print(f"Creating Cloudflare record for {full_name}: {record_type} -> {record_value}")
|
||||||
|
try:
|
||||||
|
resp = requests.post(f"{CLOUDFLARE_API}/zones/{zone_id}/dns_records",
|
||||||
|
headers=cf_headers(), json=payload)
|
||||||
|
resp.raise_for_status()
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
print(f"Error creating Cloudflare record for {full_name}: {e}")
|
||||||
|
|
||||||
|
def apply_domains():
|
||||||
|
"""Main entry point: read config and process each domain."""
|
||||||
|
try:
|
||||||
|
with open(CONFIG_PATH, "r") as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Config file not found: {CONFIG_PATH}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
domains = config.get("domains", [])
|
||||||
|
for entry in domains:
|
||||||
|
provider = entry.get("provider", "").lower()
|
||||||
|
mode = entry.get("mode")
|
||||||
|
if provider == "godaddy":
|
||||||
|
if mode == "forward":
|
||||||
|
update_godaddy_forward(entry)
|
||||||
|
elif mode == "dns":
|
||||||
|
update_godaddy_dns_record(entry)
|
||||||
|
else:
|
||||||
|
print(f"Unsupported mode '{mode}' for GoDaddy: {entry['name']}")
|
||||||
|
elif provider == "cloudflare":
|
||||||
|
if mode == "dns":
|
||||||
|
update_cloudflare_dns_record(entry)
|
||||||
|
elif mode == "forward":
|
||||||
|
print(f"Forwarding via Cloudflare API is not implemented in this script. Skipping {entry['name']}.")
|
||||||
|
else:
|
||||||
|
print(f"Unsupported mode '{mode}' for Cloudflare: {entry['name']}")
|
||||||
|
else:
|
||||||
|
print(f"Unknown provider '{provider}' for {entry['name']}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
apply_domains()
|
||||||
Reference in New Issue
Block a user