diff --git a/lib/ansible/modules/net_tools/netcup_dns.py b/lib/ansible/modules/net_tools/netcup_dns.py new file mode 100644 index 0000000000..8604887d5c --- /dev/null +++ b/lib/ansible/modules/net_tools/netcup_dns.py @@ -0,0 +1,262 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2018 Nicolai Buchwitz +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +DOCUMENTATION = ''' +--- +module: netcup_dns +notes: [] +version_added: 2.7.0 +short_description: manage Netcup DNS records +description: + - "Manages DNS records via the Netcup API, see the docs U(https://ccp.netcup.net/run/webservice/servers/endpoint.php)" +options: + api_key: + description: + - API key for authentification, must be obtained via the netcup CCP (U(https://ccp.netcup.net)) + required: True + api_password: + description: + - API password for authentification, must be obtained via the netcup CCP (https://ccp.netcup.net) + required: True + customer_id: + description: + - Netcup customer id + required: True + domain: + description: + - Domainname the records should be added / removed + required: True + record: + description: + - Record to add or delete, supports wildcard (*). Default is C(@) (e.g. the zone name) + default: "@" + aliases: [ name ] + type: + description: + - Record type + choices: ['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS'] + required: True + value: + description: + - Record value + required: true + solo: + type: bool + default: False + description: + - Whether the record should be the only one for that record type and record name. Only use with C(state=present) + - This will delete all other records with the same record name and type. + priority: + description: + - Record priority. Required for C(type=MX) + required: False + state: + description: + - Whether the record should exist or not + required: False + default: present + choices: [ 'present', 'absent' ] +requirements: + - "nc-dnsapi >= 0.1.3" +author: "Nicolai Buchwitz (@nbuchwitz)" + +''' + +EXAMPLES = ''' +- name: Create a record of type A + netcup_dns: + api_key: "..." + api_password: "..." + customer_id: "..." + domain: "example.com" + name: "mail" + type: "A" + value: "127.0.0.1" + +- name: Delete that record + netcup_dns: + api_key: "..." + api_password: "..." + customer_id: "..." + domain: "example.com" + name: "mail" + type: "A" + value: "127.0.0.1" + state: absent + +- name: Create a wildcard record + netcup_dns: + api_key: "..." + api_password: "..." + customer_id: "..." + domain: "example.com" + name: "*" + type: "A" + value: "127.0.1.1" + +- name: Set the MX record for example.com + netcup_dns: + api_key: "..." + api_password: "..." + customer_id: "..." + domain: "example.com" + type: "MX" + value: "mail.example.com" + +- name: Set a record and ensure that this is the only one + netcup_dns: + api_key: "..." + api_password: "..." + customer_id: "..." + name: "demo" + domain: "example.com" + type: "AAAA" + value: "::1" + solo: true +''' + +RETURN = ''' +records: + description: list containing all records + returned: success + type: complex + contains: + name: + description: the record name + returned: success + type: string + sample: fancy-hostname + type: + description: the record type + returned: succcess + type: string + sample: A + value: + description: the record destination + returned: success + type: string + sample: 127.0.0.1 + priority: + description: the record priority (only relevant if type=MX) + returned: success + type: int + sample: 0 + id: + description: internal id of the record + returned: success + type: int + sample: 12345 +''' + +from ansible.module_utils.basic import AnsibleModule + +try: + import nc_dnsapi + from nc_dnsapi import DNSRecord + + HAS_NCDNSAPI = True +except ImportError: + HAS_NCDNSAPI = False + + +def main(): + module = AnsibleModule( + argument_spec=dict( + api_key=dict(required=True, no_log=True), + api_password=dict(required=True, no_log=True), + customer_id=dict(required=True, type='int'), + + domain=dict(required=True), + record=dict(required=False, default='@', aliases=['name']), + type=dict(required=True, choices=['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS']), + value=dict(required=True), + priority=dict(required=False, type='int'), + solo=dict(required=False, type='bool', default=False), + state=dict(required=False, choices=['present', 'absent'], default='present'), + + ), + supports_check_mode=True + ) + + if not HAS_NCDNSAPI: + module.fail_json(msg="nc-dnsapi is required for this module") + + api_key = module.params.get('api_key') + api_password = module.params.get('api_password') + customer_id = module.params.get('customer_id') + domain = module.params.get('domain') + record_type = module.params.get('type') + record = module.params.get('record') + value = module.params.get('value') + priority = module.params.get('priority') + solo = module.params.get('solo') + state = module.params.get('state') + + if record_type == 'MX' and not priority: + module.fail_json(msg="record type MX required the 'priority' argument") + + has_changed = False + all_records = [] + try: + with nc_dnsapi.Client(customer_id, api_key, api_password) as api: + all_records = api.dns_records(domain) + record = DNSRecord(record, record_type, value, priority=priority) + + # try to get existing record + record_exists = False + for r in all_records: + if r == record: + record_exists = True + record = r + + break + + if state == 'present': + if solo: + obsolete_records = [r for r in all_records if + r.hostname == record.hostname + and r.type == record.type + and not r.destination == record.destination] + + if obsolete_records: + if not module.check_mode: + all_records = api.delete_dns_records(domain, obsolete_records) + + has_changed = True + + if not record_exists: + if not module.check_mode: + all_records = api.add_dns_record(domain, record) + + has_changed = True + elif state == 'absent' and record_exists: + if not module.check_mode: + all_records = api.delete_dns_record(domain, record) + + has_changed = True + + except Exception as ex: + module.fail_json(msg=ex.message) + + module.exit_json(changed=has_changed, result={"records": [record_data(r) for r in all_records]}) + + +def record_data(r): + return {"name": r.hostname, "type": r.type, "value": r.destination, "priority": r.priority, "id": r.id} + + +if __name__ == '__main__': + main()