219 lines
8.5 KiB
Python
219 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Alibaba Cloud DNS Record Manager
|
|
Supports: list, add, update, delete, enable, disable operations on Alidns records.
|
|
|
|
Usage:
|
|
python alidns_manager.py list --domain example.com [--rr www] [--type A]
|
|
python alidns_manager.py add --domain example.com --rr www --type A --value 1.2.3.4 [--ttl 600]
|
|
python alidns_manager.py update --record-id 123456 --rr www --type A --value 5.6.7.8 [--ttl 600]
|
|
python alidns_manager.py delete --record-id 123456
|
|
python alidns_manager.py enable --record-id 123456
|
|
python alidns_manager.py disable --record-id 123456
|
|
|
|
Environment Variables:
|
|
ALIBABA_CLOUD_ACCESS_KEY_ID - RAM sub-user Access Key ID
|
|
ALIBABA_CLOUD_ACCESS_KEY_SECRET - RAM sub-user Access Key Secret
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
try:
|
|
from alibabacloud_alidns20150109.client import Client as AlidnsClient
|
|
from alibabacloud_alidns20150109 import models as alidns_models
|
|
from alibabacloud_tea_openapi import models as open_api_models
|
|
except ImportError:
|
|
print("ERROR: Required packages not installed. Run:")
|
|
print(" pip install alibabacloud_alidns20150109 alibabacloud_tea_openapi --break-system-packages")
|
|
sys.exit(1)
|
|
|
|
|
|
def create_client(region_id: str = "cn-hangzhou") -> AlidnsClient:
|
|
"""Create an authenticated Alidns client."""
|
|
access_key_id = os.environ.get("ALIBABA_CLOUD_ACCESS_KEY_ID")
|
|
access_key_secret = os.environ.get("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
|
|
|
|
if not access_key_id or not access_key_secret:
|
|
print("ERROR: Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET env vars.")
|
|
sys.exit(1)
|
|
|
|
config = open_api_models.Config(
|
|
access_key_id=access_key_id,
|
|
access_key_secret=access_key_secret,
|
|
)
|
|
config.endpoint = f"alidns.{region_id}.aliyuncs.com"
|
|
return AlidnsClient(config)
|
|
|
|
|
|
def list_records(client: AlidnsClient, domain: str, rr: str = None, record_type: str = None, page_size: int = 100):
|
|
"""List all DNS records for a domain, with optional filtering."""
|
|
request = alidns_models.DescribeDomainRecordsRequest(
|
|
domain_name=domain,
|
|
page_size=page_size,
|
|
)
|
|
if rr:
|
|
request.rrkey_word = rr
|
|
if record_type:
|
|
request.type = record_type
|
|
|
|
try:
|
|
response = client.describe_domain_records(request)
|
|
records = response.body.domain_records.record
|
|
total = response.body.total_count
|
|
|
|
print(f"\n📋 DNS Records for {domain} (Total: {total})\n")
|
|
print(f"{'RecordId':<20} {'RR':<25} {'Type':<8} {'Value':<40} {'TTL':<6} {'Status'}")
|
|
print("-" * 120)
|
|
|
|
for r in records:
|
|
status_icon = "✅" if r.status == "ENABLE" else "⏸️"
|
|
rr_display = f"{r.rr}.{domain}" if r.rr != "@" else domain
|
|
print(f"{r.record_id:<20} {rr_display:<25} {r.type:<8} {r.value:<40} {r.ttl:<6} {status_icon} {r.status}")
|
|
|
|
return records
|
|
except Exception as e:
|
|
print(f"ERROR listing records: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
def add_record(client: AlidnsClient, domain: str, rr: str, record_type: str, value: str, ttl: int = 600):
|
|
"""Add a new DNS record."""
|
|
request = alidns_models.AddDomainRecordRequest(
|
|
domain_name=domain,
|
|
rr=rr,
|
|
type=record_type,
|
|
value=value,
|
|
ttl=ttl,
|
|
)
|
|
|
|
try:
|
|
response = client.add_domain_record(request)
|
|
record_id = response.body.record_id
|
|
fqdn = f"{rr}.{domain}" if rr != "@" else domain
|
|
print(f"✅ Added: {fqdn} -> {record_type} {value} (TTL: {ttl}, RecordId: {record_id})")
|
|
return record_id
|
|
except Exception as e:
|
|
error_msg = str(e)
|
|
if "DomainRecordDuplicate" in error_msg:
|
|
print(f"⚠️ Record already exists: {rr}.{domain} {record_type} {value}")
|
|
elif "DomainRecordConflict" in error_msg:
|
|
print(f"❌ Conflict: CNAME records cannot coexist with other record types for {rr}.{domain}")
|
|
else:
|
|
print(f"ERROR adding record: {e}")
|
|
return None
|
|
|
|
|
|
def update_record(client: AlidnsClient, record_id: str, rr: str, record_type: str, value: str, ttl: int = 600):
|
|
"""Update an existing DNS record by RecordId."""
|
|
request = alidns_models.UpdateDomainRecordRequest(
|
|
record_id=record_id,
|
|
rr=rr,
|
|
type=record_type,
|
|
value=value,
|
|
ttl=ttl,
|
|
)
|
|
|
|
try:
|
|
client.update_domain_record(request)
|
|
print(f"✅ Updated RecordId {record_id}: {rr} -> {record_type} {value} (TTL: {ttl})")
|
|
except Exception as e:
|
|
print(f"ERROR updating record: {e}")
|
|
|
|
|
|
def delete_record(client: AlidnsClient, record_id: str):
|
|
"""Delete a DNS record by RecordId."""
|
|
request = alidns_models.DeleteDomainRecordRequest(record_id=record_id)
|
|
|
|
try:
|
|
client.delete_domain_record(request)
|
|
print(f"✅ Deleted RecordId: {record_id}")
|
|
except Exception as e:
|
|
print(f"ERROR deleting record: {e}")
|
|
|
|
|
|
def set_record_status(client: AlidnsClient, record_id: str, status: str):
|
|
"""Enable or disable a DNS record."""
|
|
request = alidns_models.SetDomainRecordStatusRequest(
|
|
record_id=record_id,
|
|
status=status, # "Enable" or "Disable"
|
|
)
|
|
|
|
try:
|
|
client.set_domain_record_status(request)
|
|
icon = "✅" if status == "Enable" else "⏸️"
|
|
print(f"{icon} RecordId {record_id} status set to: {status}")
|
|
except Exception as e:
|
|
print(f"ERROR setting status: {e}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Alibaba Cloud DNS Record Manager")
|
|
subparsers = parser.add_subparsers(dest="action", help="Action to perform")
|
|
|
|
# List
|
|
list_parser = subparsers.add_parser("list", help="List DNS records")
|
|
list_parser.add_argument("--domain", required=True, help="Domain name (e.g., gogenex.com)")
|
|
list_parser.add_argument("--rr", help="Filter by subdomain prefix")
|
|
list_parser.add_argument("--type", help="Filter by record type (A, CNAME, etc.)")
|
|
list_parser.add_argument("--region", default="cn-hangzhou", help="Alidns region (default: cn-hangzhou)")
|
|
|
|
# Add
|
|
add_parser = subparsers.add_parser("add", help="Add a DNS record")
|
|
add_parser.add_argument("--domain", required=True)
|
|
add_parser.add_argument("--rr", required=True, help="Subdomain prefix (e.g., api, www, @)")
|
|
add_parser.add_argument("--type", required=True, help="Record type (A, AAAA, CNAME, MX, TXT, etc.)")
|
|
add_parser.add_argument("--value", required=True, help="Record value (IP, domain, text)")
|
|
add_parser.add_argument("--ttl", type=int, default=600, help="TTL in seconds (default: 600)")
|
|
add_parser.add_argument("--region", default="cn-hangzhou")
|
|
|
|
# Update
|
|
update_parser = subparsers.add_parser("update", help="Update a DNS record")
|
|
update_parser.add_argument("--record-id", required=True, help="RecordId to update")
|
|
update_parser.add_argument("--rr", required=True)
|
|
update_parser.add_argument("--type", required=True)
|
|
update_parser.add_argument("--value", required=True)
|
|
update_parser.add_argument("--ttl", type=int, default=600)
|
|
update_parser.add_argument("--region", default="cn-hangzhou")
|
|
|
|
# Delete
|
|
delete_parser = subparsers.add_parser("delete", help="Delete a DNS record")
|
|
delete_parser.add_argument("--record-id", required=True, help="RecordId to delete")
|
|
delete_parser.add_argument("--region", default="cn-hangzhou")
|
|
|
|
# Enable / Disable
|
|
enable_parser = subparsers.add_parser("enable", help="Enable a DNS record")
|
|
enable_parser.add_argument("--record-id", required=True)
|
|
enable_parser.add_argument("--region", default="cn-hangzhou")
|
|
|
|
disable_parser = subparsers.add_parser("disable", help="Disable a DNS record")
|
|
disable_parser.add_argument("--record-id", required=True)
|
|
disable_parser.add_argument("--region", default="cn-hangzhou")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not args.action:
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
client = create_client(args.region)
|
|
|
|
if args.action == "list":
|
|
list_records(client, args.domain, rr=args.rr, record_type=getattr(args, "type", None))
|
|
elif args.action == "add":
|
|
add_record(client, args.domain, args.rr, args.type, args.value, args.ttl)
|
|
elif args.action == "update":
|
|
update_record(client, args.record_id, args.rr, args.type, args.value, args.ttl)
|
|
elif args.action == "delete":
|
|
delete_record(client, args.record_id)
|
|
elif args.action == "enable":
|
|
set_record_status(client, args.record_id, "Enable")
|
|
elif args.action == "disable":
|
|
set_record_status(client, args.record_id, "Disable")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|