8 from datetime
import datetime
12 #boto3.setup_default_session(profile_name='sajat')
14 print('Loading function at ' + datetime
.now().time().isoformat())
15 route53
= boto3
.client('route53')
16 compute
= boto3
.client('ec2')
17 global_default_ttl
= 3600
18 (UPDATE
, DELETE
) = range(2)
22 def lambda_handler(event
, context
):
25 if event
['detail'].has_key('eventName'):
26 region
= event
['detail']['awsRegion']
27 instance_id
= event
['detail']['requestParameters']['resourcesSet']['items'][0]['resourceId'] #FIXME iterate through on all instances
28 if event
['detail']['eventName'] == 'CreateTags':
30 elif event
['detail']['eventName'] == 'DeleteTags':
33 region
= event
['region']
34 instance_id
= event
['detail']['instance-id']
35 state
= event
['detail']['state']
36 if state
== 'running':
41 # DELETE old record if exists
44 (Name
, ZoneId
, Zone
) = get_instance_name_by_id(instance_id
)
46 print("Old Name not found in DNS for %s" % instance_id
)
50 if ZoneId
is not None:
52 for record
in iter_records():
53 if record
['zone'] == Zone
and record
['type'] == 'A' and record
['name'] == Name
:
54 public_ip
= record
['content']
57 dereg
= deregister_name(ZoneId
, Zone
, Name
, instance_id
, public_ip
)
65 instance
= compute
.describe_instances(InstanceIds
=[instance_id
])
67 except botocore
.exceptions
.ClientError
:
71 public_ip
= instance
['Reservations'][0]['Instances'][0]['PublicIpAddress']
72 except BaseException
as e
:
73 print("Instance %s has no public IP" % instance_id
)
76 tags
= dict(map(lambda t
: (t
['Key'], t
['Value']), instance
['Reservations'][0]['Instances'][0]['Tags']))
78 DnsName
= tags
['dns-name']
82 Zone
= tags
['dns-zone']
83 if not Zone
.endswith('.'):
86 ZoneId
= get_zone_id_by_name(Zone
)
88 print("No such Zone with name '%s'" % Zone
)
91 print("Name and dns-zone tags or dns-name tag not found on instance %s" % instance_id
)
95 if not DnsName
.endswith('.'):
97 for record
in sorted(iter_records(), cmp = lambda a
, b
: cmp(len(b
['zone']), len(a
['zone']))):
98 suffix
= '.' + record
['zone']
99 if DnsName
.endswith(suffix
):
100 Name
= DnsName
[0:-len(suffix
)]
101 Zone
= record
['zone']
102 ZoneId
= record
['zone_id']
107 print("Zone not found for FQDN '%s'" % DnsName
)
112 return register_name(ZoneId
, Zone
, Name
, instance_id
, public_ip
)
116 if len(R53Cache
) > 0:
117 for record_dict
in R53Cache
:
120 zones
= route53
.list_hosted_zones()['HostedZones']
122 records
= route53
.list_resource_record_sets(HostedZoneId
=zone
['Id'])['ResourceRecordSets']
123 for record
in records
:
124 for rr
in record
['ResourceRecords']:
125 zone_name
= zone
['Name']
126 name
= record
['Name'][0:-len(zone_name
)-1]
127 type = record
['Type']
128 content
= rr
['Value']
130 content
= content
.strip('"')
131 record_dict
= {'zone': zone_name
, 'zone_id': zone
['Id'], 'type': type, 'name': name
, 'ttl': record
['TTL'], 'content': content
}
132 #R53Cache.append(record_dict)
135 def get_instance_name_by_id(instance_id
):
136 for record
in iter_records():
137 if record
['type'] == 'TXT' and record
['name'] == instance_id
+ '.instance-id':
138 return (record
['content'], record
['zone_id'], record
['zone'])
139 raise ValueError("No such TXT record with name '%s'" % instance_id
)
141 def get_zone_id_by_name(zone_name
):
142 for record
in iter_records():
143 if record
['zone'] == zone_name
:
144 return record
['zone_id']
145 raise ValueError("No such zone with name '%s'" % zone_name
)
147 def register_name(zone_id
, zone
, name
, instance_id
, content
):
148 fqdn
= name
+ '.' + zone
149 print("Registering: %s IN A %s, Id=%s" % (fqdn
, content
, instance_id
))
151 route53
.change_resource_record_sets(
152 HostedZoneId
= zone_id
,
154 "Comment": "Updated by Lambda DDNS",
158 "ResourceRecordSet": {
161 "TTL": global_default_ttl
,
162 "ResourceRecords": [{"Value": content
}]
167 "ResourceRecordSet": {
168 "Name": instance_id
+ '.instance-id.' + zone
,
170 "TTL": global_default_ttl
,
171 "ResourceRecords": [{"Value": '"' + name
+ '"'}]
179 def deregister_name(zone_id
, zone
, name
, instance_id
, content
):
180 fqdn
= name
+ '.' + zone
181 print("Deregistering: %s IN A %s, Id=%s" % (fqdn
, content
, instance_id
))
183 route53
.change_resource_record_sets(
184 HostedZoneId
= zone_id
,
186 "Comment": "Deleted by Lambda DDNS",
190 "ResourceRecordSet": {
193 "TTL": global_default_ttl
,
194 "ResourceRecords": [{"Value": content
}]
199 "ResourceRecordSet": {
200 "Name": instance_id
+ '.instance-id.' + zone
,
202 "TTL": global_default_ttl
,
203 "ResourceRecords": [{"Value": '"' + name
+ '"'}]