autonomic.gandi/library/gandi_dns.py

203 lines
5.1 KiB
Python
Raw Normal View History

2020-03-28 18:34:53 +00:00
#!/usr/bin/env python3
2020-03-28 00:01:56 +00:00
2020-03-28 18:34:53 +00:00
import json
import os
2020-03-28 16:55:36 +00:00
import traceback
2020-03-28 18:34:53 +00:00
from subprocess import CalledProcessError, check_output
2020-03-28 16:55:36 +00:00
2020-03-28 18:34:53 +00:00
from ansible.module_utils.basic import (
AnsibleModule,
env_fallback,
missing_required_lib,
)
2020-03-28 00:01:56 +00:00
DOCUMENTATION = """
---
module: gandi_dns
2020-03-28 16:55:36 +00:00
short_description: Manage Gandi DNS entries.
requirements:
- python >= 3.8
2020-03-28 18:34:53 +00:00
- dns-lexicon >= 3.3.19
2020-03-28 16:55:36 +00:00
author:
- Luke Murphy (@decentral1se)
options:
domain:
description: The domain name you're working with.
type: str
required: true
ipv4:
description: The IP v4 address that the domain refers to.
type: str
required: true
gandi_rest_token:
2020-03-28 18:34:53 +00:00
description:
- The Gandi REST API key. It may also be specified by the C(LEXICON_GANDI_AUTH_TOKEN)
environment variable. See U(https://github.com/AnalogJ/lexicon/blob/ce168132880558415c8c755e65f8e2f9b46cff62/lexicon/providers/gandi.py).
for more.
type: str
required: false
2020-03-28 16:55:36 +00:00
state:
description:
- The desired instance state.
type: str
choices:
- present
- absent
required: true
""" # noqa
2020-03-28 00:01:56 +00:00
EXAMPLES = """
- name: Create a new Gandi DNS entry
gandi_dns:
domain: foobar.autonomic.zone
ipv4: 192.168.1.2
2020-03-28 16:55:36 +00:00
state: present
"""
2020-03-28 18:34:53 +00:00
DNS_LEXICON_IMP_ERR = None
2020-03-28 16:55:36 +00:00
try:
2020-03-28 18:34:53 +00:00
from lexicon.providers import gandi # noqa
2020-03-28 16:55:36 +00:00
2020-03-28 18:34:53 +00:00
HAS_DNS_LEXICON_DEPENDENCY = True
2020-03-28 16:55:36 +00:00
except ImportError:
2020-03-28 18:34:53 +00:00
DNS_LEXICON_IMP_ERR = traceback.format_exc()
HAS_DNS_LEXICON_DEPENDENCY = False
def error_msg(domain):
"""Better error message since check_output output is not helpful."""
return (
"Unable to retrieve domain info. Did you export "
"the LEXICON_GANDI_AUTH_TOKEN environment variable? "
"Does running the following command work? lexicon "
"gandi list {domain} A"
).format(domain=domain)
def get_env():
"""Build environment for running command-line commands."""
env = os.environ.copy()
env["PROVIDER"] = "gandi"
env["LEXICON_GANDI_API_PROTOCOL"] = "rest"
return env
2020-03-28 18:34:53 +00:00
def retrieve_domain_info(module):
"""Retrieve all information about a specific domain."""
domain = module.params["domain"]
env = get_env()
2020-03-28 18:34:53 +00:00
try:
return json.loads(
check_output(
["lexicon", "gandi", "list", domain, "A", "--output", "JSON"],
env=env,
2020-03-28 18:34:53 +00:00
)
)
except CalledProcessError:
module.fail_json(msg=error_msg(domain))
2020-03-28 18:34:53 +00:00
def create_domain(module):
"""Create a new DNS entry."""
domain = module.params["domain"]
ipv4 = module.params["ipv4"]
env = get_env()
2020-03-28 18:34:53 +00:00
try:
return json.loads(
check_output(
[
"lexicon",
"gandi",
"create",
domain,
2020-03-28 18:34:53 +00:00
"A",
"--name",
domain,
2020-03-28 18:34:53 +00:00
"--content",
ipv4,
2020-03-28 18:34:53 +00:00
"--output",
"JSON",
],
env=env,
2020-03-28 18:34:53 +00:00
)
)
except Exception:
module.fail_json(msg=error_msg(domain))
2020-03-28 18:34:53 +00:00
def delete_domain(module):
"""Delete an existing DNS entry."""
domain = module.params["domain"]
ipv4 = module.params["ipv4"]
env = get_env()
2020-03-28 18:34:53 +00:00
try:
return json.loads(
check_output(
[
"lexicon",
"gandi",
"delete",
domain,
2020-03-28 18:34:53 +00:00
"A",
"--name",
domain,
2020-03-28 18:34:53 +00:00
"--content",
ipv4,
2020-03-28 18:34:53 +00:00
"--output",
"JSON",
],
env=env,
2020-03-28 18:34:53 +00:00
)
)
except Exception:
module.fail_json(msg=error_msg(domain))
2020-03-28 16:55:36 +00:00
2020-03-28 00:01:56 +00:00
def main():
2020-03-28 16:55:36 +00:00
"""Module entrypoint."""
2020-03-28 18:34:53 +00:00
module = AnsibleModule(
argument_spec=dict(
domain=dict(type="str", required=True),
ipv4=dict(type="str", required=True),
2020-03-28 18:34:53 +00:00
state=dict(
type="str", required=True, choices=["present", "absent"]
2020-03-28 18:34:53 +00:00
),
gandi_rest_token=dict(
type="str",
required=False,
2020-03-28 18:34:53 +00:00
no_log=True,
fallback=(env_fallback, ["LEXICON_GANDI_AUTH_TOKEN"]),
2020-03-28 18:34:53 +00:00
),
),
supports_check_mode=False,
required_together=(["domain", "ipv4"]),
2020-03-28 18:34:53 +00:00
)
if not HAS_DNS_LEXICON_DEPENDENCY:
msg = missing_required_lib("lexicon")
2020-03-28 18:34:53 +00:00
module.fail_json(msg=msg, exception=DNS_LEXICON_IMP_ERR)
domains = retrieve_domain_info(module)
existing_domain = module.params["domain"] in [
domain["name"] for domain in domains
2020-03-28 18:34:53 +00:00
]
2020-03-28 16:55:36 +00:00
if module.params["state"] == "present":
2020-03-28 18:34:53 +00:00
if existing_domain:
module.exit_json(changed=False)
create_domain(module)
module.exit_json(changed=True)
2020-03-28 16:55:36 +00:00
if module.params["state"] == "absent":
2020-03-28 18:34:53 +00:00
if not existing_domain:
module.exit_json(changed=False)
delete_domain(module)
module.exit_json(changed=True)
2020-03-28 00:01:56 +00:00
if __name__ == "__main__":
main()