-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.py
166 lines (144 loc) · 5.3 KB
/
index.py
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import csv
import json
import logging
import os
import time
from datetime import datetime
import boto3
from botocore.exceptions import ClientError
s3_client = boto3.client('s3')
route53_client = boto3.client('route53')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def upload_to_s3(folder, filename, bucket_name, key):
"""Upload a file to a folder in an Amazon S3 bucket."""
key = folder + '/' + key
s3_client.upload_file(filename, bucket_name, key)
def get_route53_hosted_zones(next_zone=None):
"""Recursively returns a list of hosted zones in Amazon Route 53."""
if(next_zone):
response = route53_client.list_hosted_zones_by_name(
DNSName=next_zone[0],
HostedZoneId=next_zone[1]
)
else:
response = route53_client.list_hosted_zones_by_name()
hosted_zones = response['HostedZones']
# if response is truncated, call function again with next zone name/id
if(response['IsTruncated']):
hosted_zones += get_route53_hosted_zones(
(response['NextDNSName'],
response['NextHostedZoneId'])
)
return hosted_zones
def get_route53_zone_records(zone_id, next_record=None):
"""Recursively returns a list of records of a hosted zone in Route 53."""
if(next_record):
response = route53_client.list_resource_record_sets(
HostedZoneId=zone_id,
StartRecordName=next_record[0],
StartRecordType=next_record[1]
)
else:
response = route53_client.list_resource_record_sets(
HostedZoneId=zone_id)
zone_records = response['ResourceRecordSets']
# if response is truncated, call function again with next record name/id
if(response['IsTruncated']):
zone_records += get_route53_zone_records(
zone_id,
(response['NextRecordName'],
response['NextRecordType'])
)
return zone_records
def get_record_value(record):
"""Return a list of values for a hosted zone record."""
# test if record's value is Alias or dict of records
try:
value = [':'.join(
['ALIAS', record['AliasTarget']['HostedZoneId'],
record['AliasTarget']['DNSName']]
)]
except KeyError:
value = []
for v in record['ResourceRecords']:
value.append(v['Value'])
return value
def try_record(test, record):
"""Return a value for a record"""
# test for Key and Type errors
try:
value = record[test]
except KeyError:
value = ''
except TypeError:
value = ''
return value
def write_zone_to_csv(zone, zone_records):
"""Write hosted zone records to a csv file in /tmp/."""
zone_file_name = '/tmp/' + zone['Name'] + 'csv'
# write to csv file with zone name
with open(zone_file_name, 'w', newline='') as csv_file:
writer = csv.writer(csv_file)
# write column headers
writer.writerow([
'NAME', 'TYPE', 'VALUE',
'TTL', 'REGION', 'WEIGHT',
'SETID', 'FAILOVER', 'EVALUATE_HEALTH'
])
# loop through all the records for a given zone
for record in zone_records:
csv_row = [''] * 9
csv_row[0] = record['Name']
csv_row[1] = record['Type']
csv_row[3] = try_record('TTL', record)
csv_row[4] = try_record('Region', record)
csv_row[5] = try_record('Weight', record)
csv_row[6] = try_record('SetIdentifier', record)
csv_row[7] = try_record('Failover', record)
csv_row[8] = try_record('EvaluateTargetHealth',
try_record('AliasTarget', record)
)
value = get_record_value(record)
# if multiple values (e.g., MX records), write each as its own row
for v in value:
csv_row[2] = v
writer.writerow(csv_row)
return zone_file_name
def write_zone_to_json(zone, zone_records):
"""Write hosted zone records to a json file in /tmp/."""
zone_file_name = '/tmp/' + zone['Name'] + 'json'
# write to json file with zone name
with open(zone_file_name, 'w') as json_file:
json.dump(zone_records, json_file, indent=4)
return zone_file_name
def handler(event, context):
logger.info("Start Route53 backup")
try:
s3_bucket_name = os.environ['s3BucketName']
except KeyError as e:
print("Warning: Environmental variable(s) not defined")
time_stamp = time.strftime("%Y-%m-%dT%H:%M:%SZ",
datetime.utcnow().utctimetuple()
)
hosted_zones = get_route53_hosted_zones()
for zone in hosted_zones:
logger.info(f"Working on Zone {zone['Name'][:-1]}")
zone_folder = (time_stamp + '/' + zone['Name'][:-1])
zone_records = get_route53_zone_records(zone['Id'])
upload_to_s3(
zone_folder,
write_zone_to_csv(zone, zone_records),
s3_bucket_name,
(zone['Name'] + 'csv')
)
upload_to_s3(
zone_folder,
write_zone_to_json(zone, zone_records),
s3_bucket_name,
(zone['Name'] + 'json')
)
logger.info("Finished Route53 backup")
return True
if __name__ == "__main__":
handler(0, 0)