You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.0 KiB
Python
143 lines
4.0 KiB
Python
#!/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 )
|