-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcloudflare_dns_migrator.py
More file actions
110 lines (98 loc) · 3.21 KB
/
cloudflare_dns_migrator.py
File metadata and controls
110 lines (98 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python3
import os
import sys
import json
import logging
import argparse
from cloudflare import Cloudflare
def parse_args():
parser = argparse.ArgumentParser(
description="Bulk update Cloudflare DNS records from old IP to a new IP"
)
parser.add_argument(
'--token', '-t',
help='Cloudflare API Token (or set CF_API_TOKEN env var)',
default=os.getenv('CF_API_TOKEN')
)
parser.add_argument(
'--old-ip', '-o',
required=True, help='Old IP address to replace'
)
parser.add_argument(
'--new-ip', '-n',
required=True, help='New IP address to set'
)
parser.add_argument(
'--type', '-r',
default='A', choices=['A','AAAA','CNAME','TXT'],
help='DNS record type to update (default: A)'
)
parser.add_argument(
'--zone', '-z',
action='append',
help='Specific zone name to process (repeatable)'
)
parser.add_argument(
'--dry-run', action='store_true',
help='Print intended changes without applying them'
)
parser.add_argument(
'--json', action='store_true',
help='Output results in JSON format'
)
parser.add_argument(
'--verbose', '-v', action='store_true',
help='Enable debug logging'
)
return parser.parse_args()
def main():
args = parse_args()
log_level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(
level=log_level,
format='%(asctime)s %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
if not args.token:
logging.error("API token not provided; use --token or CF_API_TOKEN env var")
sys.exit(1)
cf = Cloudflare(token=args.token)
results = []
for zone in cf.zones.list():
name = zone['name']
if args.zone and name not in args.zone:
logging.debug("Skipping zone %s (not in filters)", name)
continue
zone_id = zone['id']
logging.info("Processing zone %s", name)
for rec in cf.zones.dns_records.list(zone_id):
if rec['type'] != args.type or rec['content'] != args.old_ip:
continue
logging.info("Found %s record %s → %s", args.type, rec['name'], args.old_ip)
action = 'DRY-RUN' if args.dry_run else 'UPDATED'
if not args.dry_run:
cf.zones.dns_records.put(
zone_id, rec['id'],
**{
'type': rec['type'],
'name': rec['name'],
'content': args.new_ip,
'ttl': rec['ttl'],
'proxied': rec['proxied']
}
)
logging.debug("Record %s updated to %s", rec['name'], args.new_ip)
results.append({
'zone': name,
'record': rec['name'],
'old': args.old_ip,
'new': args.new_ip,
'action': action
})
if args.json:
print(json.dumps(results, indent=2))
else:
for r in results:
print(f"{r['action']}: {r['zone']} {r['record']}")
if __name__ == '__main__':
main()