232 lines
7.2 KiB
Python
232 lines
7.2 KiB
Python
#!/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 <http://www.gnu.org/licenses/>.
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: rds
|
|
version_added: "1.4"
|
|
short_description: add or delete entries in Amazons Route53 DNS service
|
|
description:
|
|
- Creates and deletes DNS records in Amazons 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 IPs
|
|
- 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 A record using the results from the get command
|
|
- route53: >
|
|
command=delete
|
|
zone=foo.com
|
|
record={{ r.set.record }}
|
|
type={{ r.set.type }}
|
|
value={{ r.set.value }}
|
|
|
|
# Add an AAAA record. Note that because there are colons in the value
|
|
# that the entire parameter list must be quoted:
|
|
- route53: >
|
|
"command=create
|
|
zone=foo.com
|
|
record=localhost.foo.com
|
|
type=AAAA
|
|
ttl=7200
|
|
value=::1"
|
|
'''
|
|
|
|
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("<Message>")[1]
|
|
txt = txt.split("</Message>")[0]
|
|
module.fail_json(msg = txt)
|
|
|
|
module.exit_json(changed=True)
|
|
|
|
# this is magic, see lib/ansible/module_common.py
|
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
|
|
|
main()
|