1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-02-04 16:01:55 +00:00
community.general/plugins/modules/netcup_dns.py
Felix Fontein 3478863ef0
Address issues reported by ruff check (#11043)
* Resolve E713 and E714 (not in/is tests).

* Address UP018 (unnecessary str call).

* UP045 requires Python 3.10+.

* Address UP007 (X | Y for type annotations).

* Address UP035 (import Callable from collections.abc).

* Address UP006 (t.Dict -> dict).

* Address UP009 (UTF-8 encoding comment).

* Address UP034 (extraneous parantheses).

* Address SIM910 (dict.get() with None default).

* Address F401 (unused import).

* Address UP020 (use builtin open).

* Address B009 and B010 (getattr/setattr with constant name).

* Address SIM300 (Yoda conditions).

* UP029 isn't in use anyway.

* Address FLY002 (static join).

* Address B034 (re.sub positional args).

* Address B020 (loop variable overrides input).

* Address B017 (assert raise Exception).

* Address SIM211 (if expression with false/true).

* Address SIM113 (enumerate for loop).

* Address UP036 (sys.version_info checks).

* Remove unnecessary UP039.

* Address SIM201 (not ==).

* Address SIM212 (if expr with twisted arms).

* Add changelog fragment.

* Reformat.
2025-11-08 17:05:21 +13:00

313 lines
8.5 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: none
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).
required: false
type: int
state:
description:
- Whether the record should exist or not.
required: false
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
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)
# 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)
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=str(ex))
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()