mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-02-04 07:51:50 +00:00
329 lines
9.2 KiB
Python
329 lines
9.2 KiB
Python
#!/usr/bin/python
|
|
|
|
# Copyright (c) 2018 Nicolai Buchwitz <nb@tipi-net.de>
|
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
from __future__ import annotations
|
|
|
|
DOCUMENTATION = r"""
|
|
module: netcup_dns
|
|
notes: []
|
|
short_description: Manage Netcup DNS records
|
|
description:
|
|
- Manages DNS records using the Netcup API, see the docs U(https://ccp.netcup.net/run/webservice/servers/endpoint.php).
|
|
extends_documentation_fragment:
|
|
- community.general.attributes
|
|
attributes:
|
|
check_mode:
|
|
support: full
|
|
diff_mode:
|
|
support: full
|
|
version_added: 12.3.0
|
|
options:
|
|
api_key:
|
|
description:
|
|
- API key for authentication, must be obtained using the netcup CCP (U(https://ccp.netcup.net)).
|
|
required: true
|
|
type: str
|
|
api_password:
|
|
description:
|
|
- API password for authentication, must be obtained using the netcup CCP (U(https://ccp.netcup.net)).
|
|
required: true
|
|
type: str
|
|
customer_id:
|
|
description:
|
|
- Netcup customer ID.
|
|
required: true
|
|
type: int
|
|
domain:
|
|
description:
|
|
- Domainname the records should be added / removed.
|
|
required: true
|
|
type: str
|
|
record:
|
|
description:
|
|
- Record to add or delete, supports wildcard (V(*)). Default is V(@) (that is, the zone name).
|
|
default: "@"
|
|
aliases: [name]
|
|
type: str
|
|
type:
|
|
description:
|
|
- Record type.
|
|
- Support for V(OPENPGPKEY), V(SMIMEA) and V(SSHFP) was added in community.general 8.1.0.
|
|
- Record types V(OPENPGPKEY) and V(SMIMEA) require nc-dnsapi >= 0.1.5.
|
|
- Record type V(SSHFP) requires nc-dnsapi >= 0.1.6.
|
|
choices: ['A', 'AAAA', 'MX', 'CNAME', 'CAA', 'SRV', 'TXT', 'TLSA', 'NS', 'DS', 'OPENPGPKEY', 'SMIMEA', 'SSHFP']
|
|
required: true
|
|
type: str
|
|
value:
|
|
description:
|
|
- Record value.
|
|
required: true
|
|
type: str
|
|
solo:
|
|
type: bool
|
|
default: false
|
|
description:
|
|
- Whether the record should be the only one for that record type and record name. Only use with O(state=present).
|
|
- This deletes all other records with the same record name and type.
|
|
priority:
|
|
description:
|
|
- Record priority. Required for O(type=MX).
|
|
type: int
|
|
state:
|
|
description:
|
|
- Whether the record should exist or not.
|
|
default: present
|
|
choices: ['present', 'absent']
|
|
type: str
|
|
timeout:
|
|
description:
|
|
- HTTP(S) connection timeout in seconds.
|
|
default: 5
|
|
type: int
|
|
version_added: 5.7.0
|
|
requirements:
|
|
- "nc-dnsapi >= 0.1.3"
|
|
author: "Nicolai Buchwitz (@nbuchwitz)"
|
|
"""
|
|
|
|
EXAMPLES = r"""
|
|
- name: Create a record of type A
|
|
community.general.netcup_dns:
|
|
api_key: "..."
|
|
api_password: "..."
|
|
customer_id: "..."
|
|
domain: "example.com"
|
|
name: "mail"
|
|
type: "A"
|
|
value: "127.0.0.1"
|
|
|
|
- name: Delete that record
|
|
community.general.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
|
|
community.general.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
|
|
community.general.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
|
|
community.general.netcup_dns:
|
|
api_key: "..."
|
|
api_password: "..."
|
|
customer_id: "..."
|
|
name: "demo"
|
|
domain: "example.com"
|
|
type: "AAAA"
|
|
value: "::1"
|
|
solo: true
|
|
|
|
- name: Increase the connection timeout to avoid problems with an unstable connection
|
|
community.general.netcup_dns:
|
|
api_key: "..."
|
|
api_password: "..."
|
|
customer_id: "..."
|
|
domain: "example.com"
|
|
name: "mail"
|
|
type: "A"
|
|
value: "127.0.0.1"
|
|
timeout: 30
|
|
"""
|
|
|
|
RETURN = r"""
|
|
records:
|
|
description: List containing all records.
|
|
returned: success
|
|
type: list
|
|
elements: dict
|
|
contains:
|
|
name:
|
|
description: The record name.
|
|
returned: success
|
|
type: str
|
|
sample: fancy-hostname
|
|
type:
|
|
description: The record type.
|
|
returned: success
|
|
type: str
|
|
sample: A
|
|
value:
|
|
description: The record destination.
|
|
returned: success
|
|
type: str
|
|
sample: 127.0.0.1
|
|
priority:
|
|
description: The record priority (only relevant if RV(records[].type=MX)).
|
|
returned: success
|
|
type: int
|
|
sample: 0
|
|
id:
|
|
description: Internal ID of the record.
|
|
returned: success
|
|
type: int
|
|
sample: 12345
|
|
"""
|
|
|
|
import traceback
|
|
|
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
|
|
|
NCDNSAPI_IMP_ERR = None
|
|
try:
|
|
import nc_dnsapi
|
|
from nc_dnsapi import DNSRecord
|
|
|
|
HAS_NCDNSAPI = True
|
|
except ImportError:
|
|
NCDNSAPI_IMP_ERR = traceback.format_exc()
|
|
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(default="@", aliases=["name"]),
|
|
type=dict(
|
|
required=True,
|
|
choices=[
|
|
"A",
|
|
"AAAA",
|
|
"MX",
|
|
"CNAME",
|
|
"CAA",
|
|
"SRV",
|
|
"TXT",
|
|
"TLSA",
|
|
"NS",
|
|
"DS",
|
|
"OPENPGPKEY",
|
|
"SMIMEA",
|
|
"SSHFP",
|
|
],
|
|
),
|
|
value=dict(required=True),
|
|
priority=dict(type="int"),
|
|
solo=dict(type="bool", default=False),
|
|
state=dict(choices=["present", "absent"], default="present"),
|
|
timeout=dict(type="int", default=5),
|
|
),
|
|
supports_check_mode=True,
|
|
)
|
|
|
|
if not HAS_NCDNSAPI:
|
|
module.fail_json(msg=missing_required_lib("nc-dnsapi"), exception=NCDNSAPI_IMP_ERR)
|
|
|
|
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")
|
|
timeout = module.params.get("timeout")
|
|
|
|
if record_type == "MX" and not priority:
|
|
module.fail_json(msg="record type MX required the 'priority' argument")
|
|
|
|
has_changed = False
|
|
|
|
diff_mode = module._diff
|
|
diff = None
|
|
|
|
all_records = []
|
|
try:
|
|
with nc_dnsapi.Client(customer_id, api_key, api_password, timeout) as api:
|
|
all_records = api.dns_records(domain)
|
|
record = DNSRecord(record, record_type, value, priority=priority)
|
|
|
|
if diff_mode:
|
|
diff_after = all_records.copy()
|
|
# 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 r.destination != record.destination
|
|
]
|
|
|
|
if obsolete_records:
|
|
if not module.check_mode:
|
|
all_records = api.delete_dns_records(domain, obsolete_records)
|
|
|
|
if diff_mode:
|
|
diff_after = [r for r in diff_after if r not in obsolete_records]
|
|
has_changed = True
|
|
|
|
if not record_exists:
|
|
if not module.check_mode:
|
|
all_records = api.add_dns_record(domain, record)
|
|
|
|
if diff_mode:
|
|
diff_after.append(record)
|
|
has_changed = True
|
|
elif state == "absent" and record_exists:
|
|
if not module.check_mode:
|
|
all_records = api.delete_dns_record(domain, record)
|
|
|
|
if diff_mode:
|
|
diff_after.remove(record)
|
|
has_changed = True
|
|
if diff_mode:
|
|
diff = dict(before=into_diffable(all_records, domain), after=into_diffable(diff_after, domain))
|
|
|
|
except Exception as ex:
|
|
module.fail_json(msg=str(ex))
|
|
|
|
module.exit_json(changed=has_changed, diff=diff, 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}
|
|
|
|
|
|
def into_diffable(records, domain):
|
|
return {domain: [record_data(r) for r in records]}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|