From a5e9057752be809d7d73f8b1003740daf9930b6b Mon Sep 17 00:00:00 2001 From: Bruce Pennypacker Date: Thu, 18 Jul 2013 13:45:00 -0400 Subject: [PATCH] AWS route53 module --- library/cloud/route53 | 222 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 library/cloud/route53 diff --git a/library/cloud/route53 b/library/cloud/route53 new file mode 100644 index 0000000000..ea7406c426 --- /dev/null +++ b/library/cloud/route53 @@ -0,0 +1,222 @@ +#!/usr/bin/python +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: rds +version_added: "1.4" +short_description: add or delete entries in Amazon's Route53 DNS service +description: + - Creates and deletes DNS records in Amazon's Route53 service +options: + command: + description: + - Specifies the action to take. + required: true + default: null + aliases: [] + choices: [ 'get', 'create', 'delete' ] + zone: + description: + - The DNS zone to modify + required: true + default: null + aliases: [] + record: + description: + - The full DNS record to create or delete + required: true + default: null + aliases: [] + ttl: + description: + - The TTL to give the new record + required: false + default: 3600 (one hour) + aliases: [] + type: + description: + - The type of DNS record to create + required: true + default: null + aliases: [] + choices: [ 'A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS' ] + value: + description: + - The new value when creating a DNS record. Multiple comma-spaced values are allowed. When deleting a record all values for the record must be specified or Route53 will not delete it. + required: false + default: null + aliases: [] + ec2_secret_key: + description: + - EC2 secret key. If not specified then the EC2_SECRET_KEY environment variable is used. + required: false + default: null + aliases: [] + ec2_access_key: + description: + - EC2 access key. If not specified then the EC2_ACCESS_KEY environment variable is used. + required: false + default: null + aliases: [] +requirements: [ "boto" ] +author: Bruce Pennypacker +''' + +EXAMPLES = ''' +# Add new.foo.com as an A record with 3 IP's +- route53: > + command=create + zone=foo.com + record=new.foo.com + type=A + ttl=7200 + value=1.1.1.1,2.2.2.2,3.3.3.3 + +# Retrieve the details for new.foo.com +- route53: > + command=get + zone=foo.com + record=new.foo.com + type=A + register: rec + +# Delete new.foo.com's A record using the results from the 'get' +- route53: > + command=delete + zone=foo.com + record={{ r.set.record }} + type={{ r.set.type }} + value={{ r.set.value }} +.'' + +import sys + +try: + import boto + from boto import route53 + from boto.route53.record import ResourceRecordSets +except ImportError: + print "failed=True msg='boto required for this module'" + sys.exit(1) + +def main(): + module = AnsibleModule( + argument_spec = dict( + command = dict(choices=['get', 'create', 'delete'], required=True), + zone = dict(required=True), + record = dict(required=True), + ttl = dict(required=False, default=3600), + type = dict(choices=['A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS'], required=True), + value = dict(required=False), + ec2_secret_key = dict(aliases=['EC2_SECRET_KEY'], no_log=True, required=False), + ec2_access_key = dict(aliases=['EC2_ACCESS_KEY'], required=False) + ) + ) + + command_in = module.params.get('command') + zone_in = module.params.get('zone'); + ttl_in = module.params.get('ttl'); + record_in = module.params.get('record'); + type_in = module.params.get('type'); + value_in = module.params.get('value'); + ec2_secret_key = module.params.get('ec2_secret_key') + ec2_access_key = module.params.get('ec2_access_key') + + value_list = () + + if type(value_in) is str: + if value_in: + value_list = sorted(value_in.split(',')) + elif type(value_in) is list: + value_list = sorted(value_in) + + if zone_in[-1:] != '.': + zone_in += "." + + if record_in[-1:] != '.': + record_in += "." + + if command_in == 'create' or command_in == 'delete': + if not value_in: + module.fail_json(msg = "parameter 'value' required for create/delete") + + # allow environment variables to be used if ansible vars aren't set + if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ: + ec2_secret_key = os.environ['EC2_SECRET_KEY'] + if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: + ec2_access_key = os.environ['EC2_ACCESS_KEY'] + + # connect to the route53 endpoint + try: + conn = boto.route53.connection.Route53Connection(ec2_access_key, ec2_secret_key) + 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']: + zone_id = r53zone['Id'].replace('/hostedzone/', '') + zones[r53zone['Name']] = zone_id + + # Verify that the requested zone is already defined in Route53 + if not zone_in in zones: + 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]) + for rset in sets: + if rset.type == type_in and rset.name == record_in: + found_record = True + record['zone'] = zone_in + record['type'] = rset.type + record['record'] = rset.name + record['ttl'] = rset.ttl + record['value'] = ','.join(sorted(rset.resource_records)) + record['values'] = sorted(rset.resource_records) + if value_list == sorted(rset.resource_records) and command_in == 'create': + module.exit_json(changed=False) + + if command_in == 'get': + module.exit_json(changed=False, set=record) + + if command_in == 'delete' and not found_record: + module.exit_json(changed=False) + + changes = ResourceRecordSets(conn, zones[zone_in]) + + 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: + change.add_value(v) + + try: + result = changes.commit() + except boto.route53.exception.DNSServerError, e: + txt = e.body.split("")[1] + txt = txt.split("")[0] + module.fail_json(msg = txt) + + module.exit_json(changed=True) + +# this is magic, see lib/ansible/module_common.py +#<> + +main()