#!/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 . ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.0'} DOCUMENTATION = ''' module: route53_zone short_description: add or delete Route53 zones description: - Creates and deletes Route53 private and public zones version_added: "2.0" options: zone: description: - "The DNS zone record (eg: foo.com.)" required: true state: description: - whether or not the zone should exist or not required: false default: true choices: [ "present", "absent" ] vpc_id: description: - The VPC ID the zone should be a part of (if this is going to be a private zone) required: false default: null vpc_region: description: - The VPC Region the zone should be a part of (if this is going to be a private zone) required: false default: null comment: description: - Comment associated with the zone required: false default: '' extends_documentation_fragment: - aws - ec2 author: "Christopher Troup (@minichate)" ''' EXAMPLES = ''' # create a public zone - route53_zone: zone: example.com state: present comment: this is an example # delete a public zone - route53_zone: zone: example.com state: absent - name: private zone for devel route53_zone: zone: devel.example.com state: present vpc_id: '{{ myvpc_id }}' comment: developer domain # more complex example - name: register output after creating zone in parameterized region route53_zone: vpc_id: '{{ vpc.vpc_id }}' vpc_region: '{{ ec2_region }}' zone: '{{ vpc_dns_zone }}' state: present register: zone_out - debug: var: zone_out ''' RETURN=''' comment: description: optional hosted zone comment returned: when hosted zone exists type: string sample: "Private zone" name: description: hosted zone name returned: when hosted zone exists type: string sample: "private.local." private_zone: description: whether hosted zone is private or public returned: when hosted zone exists type: bool sample: true vpc_id: description: id of vpc attached to private hosted zone returned: for private hosted zone type: string sample: "vpc-1d36c84f" vpc_region: description: region of vpc attached to private hosted zone returned: for private hosted zone type: string sample: "eu-west-1" zone_id: description: hosted zone id returned: when hosted zone exists type: string sample: "Z6JQG9820BEFMW" ''' try: import boto import boto.ec2 from boto import route53 from boto.route53 import Route53Connection from boto.route53.zone import Zone HAS_BOTO = True except ImportError: HAS_BOTO = False from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.ec2 import ec2_argument_spec, get_aws_connection_info def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( zone=dict(required=True), state=dict(default='present', choices=['present', 'absent']), vpc_id=dict(default=None), vpc_region=dict(default=None), comment=dict(default=''))) module = AnsibleModule(argument_spec=argument_spec) if not HAS_BOTO: module.fail_json(msg='boto required for this module') zone_in = module.params.get('zone').lower() state = module.params.get('state').lower() vpc_id = module.params.get('vpc_id') vpc_region = module.params.get('vpc_region') comment = module.params.get('comment') if zone_in[-1:] != '.': zone_in += "." private_zone = vpc_id is not None and vpc_region is not None _, _, aws_connect_kwargs = get_aws_connection_info(module) # connect to the route53 endpoint try: conn = Route53Connection(**aws_connect_kwargs) except boto.exception.BotoServerError as e: module.fail_json(msg=e.error_message) results = conn.get_all_hosted_zones() zones = {} for r53zone in results['ListHostedZonesResponse']['HostedZones']: zone_id = r53zone['Id'].replace('/hostedzone/', '') zone_details = conn.get_hosted_zone(zone_id)['GetHostedZoneResponse'] if vpc_id and 'VPCs' in zone_details: # this is to deal with this boto bug: https://github.com/boto/boto/pull/2882 if isinstance(zone_details['VPCs'], dict): if zone_details['VPCs']['VPC']['VPCId'] == vpc_id: zones[r53zone['Name']] = zone_id else: # Forward compatibility for when boto fixes that bug if vpc_id in [v['VPCId'] for v in zone_details['VPCs']]: zones[r53zone['Name']] = zone_id else: zones[r53zone['Name']] = zone_id record = { 'private_zone': private_zone, 'vpc_id': vpc_id, 'vpc_region': vpc_region, 'comment': comment, } if state == 'present' and zone_in in zones: if private_zone: details = conn.get_hosted_zone(zones[zone_in]) if 'VPCs' not in details['GetHostedZoneResponse']: module.fail_json( msg="Can't change VPC from public to private" ) vpc_details = details['GetHostedZoneResponse']['VPCs']['VPC'] current_vpc_id = vpc_details['VPCId'] current_vpc_region = vpc_details['VPCRegion'] if current_vpc_id != vpc_id: module.fail_json( msg="Can't change VPC ID once a zone has been created" ) if current_vpc_region != vpc_region: module.fail_json( msg="Can't change VPC Region once a zone has been created" ) record['zone_id'] = zones[zone_in] record['name'] = zone_in module.exit_json(changed=False, set=record) elif state == 'present': result = conn.create_hosted_zone(zone_in, **record) hosted_zone = result['CreateHostedZoneResponse']['HostedZone'] zone_id = hosted_zone['Id'].replace('/hostedzone/', '') record['zone_id'] = zone_id record['name'] = zone_in module.exit_json(changed=True, set=record) elif state == 'absent' and zone_in in zones: conn.delete_hosted_zone(zones[zone_in]) module.exit_json(changed=True) elif state == 'absent': module.exit_json(changed=False) if __name__ == '__main__': main()