commit
93081cd6fc
3 changed files with 168 additions and 0 deletions
Binary file not shown.
@ -0,0 +1,142 @@ |
||||
#!/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 ) |
@ -0,0 +1,26 @@ |
||||
{ |
||||
"Version": "2012-10-17", |
||||
"Statement": [ |
||||
{ |
||||
"Action": [ |
||||
"route53:ChangeResourceRecordSets", |
||||
"route53:GetHostedZone", |
||||
"route53:ListResourceRecordSets" |
||||
], |
||||
"Effect": "Allow", |
||||
"Resource": [ |
||||
"arn:aws:route53:::hostedzone/[ZONEID]", |
||||
] |
||||
}, |
||||
{ |
||||
"Action": [ |
||||
"route53:ListHostedZones", |
||||
"ec2:DescribeInstances" |
||||
], |
||||
"Effect": "Allow", |
||||
"Resource": [ |
||||
"*" |
||||
] |
||||
} |
||||
] |
||||
} |
Loading…
Reference in new issue