@ -93,6 +93,45 @@ options:
required : false
default : false
version_added : " 1.9 "
identifier :
description :
- Weighted and latency - based resource record sets only . An identifier
that differentiates among multiple resource record sets that have the
same combination of DNS name and type .
required : false
default : null
version_added : " 2.0 "
weight :
description :
- Weighted resource record sets only . Among resource record sets that
have the same combination of DNS name and type , a value that
determines what portion of traffic for the current resource record set
is routed to the associated location .
required : false
default : null
version_added : " 2.0 "
region :
description :
- Latency - based resource record sets only Among resource record sets
that have the same combination of DNS name and type , a value that
determines which region this should be associated with for the
latency - based routing
required : false
default : null
version_added : " 2.0 "
health_check :
description :
- Health check to associate with this record
required : false
default : null
version_added : " 2.0 "
failover :
description :
- Failover resource record sets only . Whether this is the primary or
secondary resource record set .
required : false
default : null
version_added : " 2.0 "
author : " Bruce Pennypacker (@bpennypacker) "
extends_documentation_fragment : aws
'''
@ -156,6 +195,18 @@ EXAMPLES = '''
alias = True
alias_hosted_zone_id = " {{ elb_zone_id }} "
# Use a routing policy to distribute traffic:
- route53 :
command : " create "
zone : " foo.com "
record : " www.foo.com "
type : " CNAME "
value : " host1.foo.com "
ttl : 30
# Routing policy
identifier : " host1@www "
weight : 100
health_check : " d994b780-3150-49fd-9205-356abdd42e75 "
'''
@ -165,11 +216,21 @@ try:
import boto
from boto import route53
from boto . route53 import Route53Connection
from boto . route53 . record import Re sourceRecordSets
from boto . route53 . record import Re cord, Re sourceRecordSets
HAS_BOTO = True
except ImportError :
HAS_BOTO = False
def get_zone_by_name ( conn , module , zone_name , want_private ) :
""" Finds a zone by name """
for zone in conn . get_zones ( ) :
# only save this zone id if the private status of the zone matches
# the private_zone_in boolean specified in the params
private_zone = module . boolean ( zone . config . get ( ' PrivateZone ' , False ) )
if private_zone == want_private and zone . name == zone_name :
return zone
return None
def commit ( changes , retry_interval ) :
""" Commit changes, but retry PriorRequestNotComplete errors. """
@ -199,6 +260,11 @@ def main():
overwrite = dict ( required = False , type = ' bool ' ) ,
retry_interval = dict ( required = False , default = 500 )
private_zone = dict ( required = False , type = ' bool ' , default = False ) ,
identifier = dict ( required = False ) ,
weight = dict ( required = False , type = ' int ' ) ,
region = dict ( required = False ) ,
health_check = dict ( required = False ) ,
failover = dict ( required = False ) ,
)
)
module = AnsibleModule ( argument_spec = argument_spec )
@ -215,6 +281,11 @@ def main():
alias_hosted_zone_id_in = module . params . get ( ' alias_hosted_zone_id ' )
retry_interval_in = module . params . get ( ' retry_interval ' )
private_zone_in = module . params . get ( ' private_zone ' )
identifier_in = module . params . get ( ' identifier ' )
weight_in = module . params . get ( ' weight ' )
region_in = module . params . get ( ' region ' )
health_check_in = module . params . get ( ' health_check ' )
failover_in = module . params . get ( ' failover ' )
region , ec2_url , aws_connect_kwargs = get_aws_connection_info ( module )
@ -247,32 +318,34 @@ def main():
except boto . exception . BotoServerError , e :
module . fail_json ( msg = e . error_message )
# Get all the existing hosted zones and save their ID's
zones = { }
results = conn . get_all_hosted_zones ( )
for r53zone in results [ ' ListHostedZonesResponse ' ] [ ' HostedZones ' ] :
# only save this zone id if the private status of the zone matches
# the private_zone_in boolean specified in the params
if module . boolean ( r53zone [ ' Config ' ] . get ( ' PrivateZone ' , False ) ) == private_zone_in :
zone_id = r53zone [ ' Id ' ] . replace ( ' /hostedzone/ ' , ' ' )
zones [ r53zone [ ' Name ' ] ] = zone_id
# Find the named zone ID
zone = get_zone_by_name ( conn , module , zone_in , private_zone_in )
# Verify that the requested zone is already defined in Route53
if not zone_in in zones :
if zone is None :
errmsg = " Zone %s does not exist in Route53 " % zone_in
module . fail_json ( msg = errmsg )
record = { }
found_record = False
sets = conn . get_all_rrsets ( zones [ zone_in ] )
wanted_rset = Record ( name = record_in , type = type_in , ttl = ttl_in ,
identifier = identifier_in , weight = weight_in , region = region_in ,
health_check = health_check_in , failover = failover_in )
for v in value_list :
if alias_in :
wanted_rset . set_alias ( alias_hosted_zone_id_in , v )
else :
wanted_rset . add_value ( v )
sets = conn . get_all_rrsets ( zone . id , name = record_in , type = type_in , identifier = identifier_in )
for rset in sets :
# Due to a bug in either AWS or Boto, "special" characters are returned as octals, preventing round
# tripping of things like * and @.
decoded_name = rset . name . replace ( r ' \ 052 ' , ' * ' )
decoded_name = decoded_name . replace ( r ' \ 100 ' , ' @ ' )
if rset . type == type_in and decoded_name . lower ( ) == record_in . lower ( ) :
if rset . type == type_in and decoded_name . lower ( ) == record_in . lower ( ) and rset . identifier == identifier_in :
found_record = True
record [ ' zone ' ] = zone_in
record [ ' type ' ] = rset . type
@ -280,6 +353,11 @@ def main():
record [ ' ttl ' ] = rset . ttl
record [ ' value ' ] = ' , ' . join ( sorted ( rset . resource_records ) )
record [ ' values ' ] = sorted ( rset . resource_records )
record [ ' identifier ' ] = rset . identifier
record [ ' weight ' ] = rset . weight
record [ ' region ' ] = rset . region
record [ ' failover ' ] = rset . failover
record [ ' health_check ' ] = rset . health_check
if rset . alias_dns_name :
record [ ' alias ' ] = True
record [ ' value ' ] = rset . alias_dns_name
@ -289,8 +367,9 @@ def main():
record [ ' alias ' ] = False
record [ ' value ' ] = ' , ' . join ( sorted ( rset . resource_records ) )
record [ ' values ' ] = sorted ( rset . resource_records )
if value_list == sorted ( rset . resource_records ) and int ( record [ ' ttl ' ] ) == ttl_in and command_in == ' create ' :
if command_in == ' create ' and rset . to_xml ( ) == wanted_rset . to_xml ( ) :
module . exit_json ( changed = False )
break
if command_in == ' get ' :
module . exit_json ( changed = False , set = record )
@ -298,26 +377,16 @@ def main():
if command_in == ' delete ' and not found_record :
module . exit_json ( changed = False )
changes = ResourceRecordSets ( conn , zone s[ zone_in ] )
changes = ResourceRecordSets ( conn , zone . id )
if command_in == ' create ' or command_in == ' delete ' :
if command_in == ' create ' and found_record :
if not module . params [ ' overwrite ' ] :
module . fail_json ( msg = " Record already exists with different value. Set ' overwrite ' to replace it " )
command = ' UPSERT '
else :
change = changes . add_change ( " DELETE " , record_in , type_in , record [ ' ttl ' ] )
for v in record [ ' values ' ] :
if record [ ' alias ' ] :
change . set_alias ( record [ ' alias_hosted_zone_id ' ] , v )
else :
change . add_value ( v )
if command_in == ' create ' or command_in == ' delete ' :
change = changes . add_change ( command_in . upper ( ) , record_in , type_in , ttl_in )
for v in value_list :
if module . params [ ' alias ' ] :
change . set_alias ( alias_hosted_zone_id_in , v )
else :
change . add_value ( v )
command = command_in . upper ( )
changes . add_change_record ( command , wanted_rset )
try :
result = commit ( changes , retry_interval_in )