You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
4.0 KiB
142 lines
4.0 KiB
#!/usr/bin/python |
|
# |
|
# Dynamically update DNS records when the EC2 instance boots. |
|
# Requires boto3 installed on the instance. |
|
# Requries an IAM policy attached to an instance role. |
|
# |
|
|
|
import urllib2 |
|
from boto3.session import Session |
|
import boto3 |
|
import datetime |
|
|
|
def getRegion(): |
|
url = "http://169.254.169.254/2009-04-04/meta-data/placement/availability-zone" |
|
try: |
|
resp = urllib2.urlopen(urllib2.Request(url)) |
|
# Region will be a string like eu-central-1a. This chops the last character off. |
|
region = resp.read()[:-1] |
|
except urllib2.HTTPError as e: |
|
if e.code == 404: |
|
return None |
|
if e.code == 500: |
|
return None |
|
raise |
|
|
|
return region |
|
|
|
def getInstanceId(): |
|
url = "http://169.254.169.254/2009-04-04/meta-data/instance-id" |
|
try: |
|
resp = urllib2.urlopen(urllib2.Request(url)) |
|
instanceid = resp.read() |
|
except urllib2.HTTPError as e: |
|
if e.code == 404: |
|
return None |
|
if e.code == 500: |
|
return None |
|
raise |
|
|
|
return instanceid |
|
|
|
def getPublicIP(): |
|
url = "http://169.254.169.254/2009-04-04/meta-data/public-ipv4" |
|
try: |
|
resp = urllib2.urlopen(urllib2.Request(url)) |
|
value = resp.read() |
|
except urllib2.HTTPError as e: |
|
if e.code == 404: |
|
return None |
|
if e.code == 500: |
|
return None |
|
raise |
|
|
|
return value |
|
|
|
# Get region and instance ID |
|
myregion = getRegion() |
|
myinstance = getInstanceId() |
|
myipv4 = getPublicIP() |
|
|
|
if( myregion == None or myinstance == None or myipv4 == None): |
|
print "ERROR: Could not get instance metadata. Abort." |
|
exit( -1 ) |
|
|
|
# Connect to EC2 and get the instance handle for this instance |
|
ec2 = boto3.resource('ec2', region_name=myregion) |
|
instance = ec2.Instance(myinstance) |
|
|
|
# Grab the tags associated with this instance |
|
mytags = instance.tags |
|
dnsname = None |
|
|
|
# Get host tag or bail |
|
for tag in instance.tags: |
|
if( tag['Key'] == 'dnsname'): |
|
dnsname = tag['Value'] |
|
|
|
if (dnsname == None): |
|
print "Did not find dnsname tag. " |
|
exit( -1 ) |
|
|
|
# Get just the domain part of dnsname |
|
myzone = dnsname.partition(".")[2] |
|
|
|
# Get zoneid for zone or bail |
|
session = Session(region_name=myregion) |
|
client = session.client('route53') |
|
# Note: if you have more than 100 hosted zones, there's a chance that |
|
# the zone you need won't be returned in response to the first call |
|
# to list_hosted_zones(). The next loop will fail to find your zone. |
|
# |
|
# If this applies to you, you have to rewrite this section to use |
|
# pagination to iterate over the collection of returned domains, |
|
# looking for the one you want. That extension is left as an |
|
# exercise for the reader. |
|
myzoneid = None |
|
zones = client.list_hosted_zones() |
|
|
|
# Route53 will return zones in canonical form with the trailing dot. |
|
# e.g.: "ec2.example.com." |
|
# It's likely that people will enter dnsnames in the tags without the |
|
# trailing dot, so this helps make the match either way. |
|
for zone in zones['HostedZones']: |
|
if( (zone['Name'] == myzone) or (zone['Name'] == myzone + ".")): |
|
myzoneid = zone['Id'] |
|
|
|
if( myzoneid == '' ): |
|
# didn't find the zone |
|
print "ERROR: Did not find " + myzone + " among the hosted zones." |
|
exit( -1 ) |
|
|
|
# Create record set update |
|
print "setting " + dnsname + " to " + myipv4 |
|
now = datetime.datetime.now() |
|
|
|
response = client.change_resource_record_sets( |
|
HostedZoneId=myzoneid, |
|
ChangeBatch={ |
|
'Comment': 'Instance ' + myinstance + ' boot at ' + now.strftime("%Y-%m-%d %H:%M"), |
|
'Changes': [ |
|
{ |
|
'Action': 'UPSERT', |
|
'ResourceRecordSet': { |
|
'TTL': 300, |
|
'Name': dnsname, |
|
'Type': 'A', |
|
'ResourceRecords': [ |
|
{ |
|
'Value': myipv4 |
|
}, |
|
] |
|
} |
|
}, |
|
] |
|
} |
|
) |
|
|
|
# Check for error. |
|
if( response['ResponseMetadata']['HTTPStatusCode'] != 200 ): |
|
print "ERROR updating Route53" |
|
print response |
|
exit( -1 )
|
|
|