diff --git a/README.md b/README.md index 65d8748..3a06b11 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Ansible libraries for managing Gandi resources. tasks: - name: Create foobar.autonomic.zone gandi_dns: - rest_api_key: "{{ lookup('env', 'LEXICON_GANDI_AUTH_TOKEN') }}" + gandi_rest_token: abc... domain: foobar.autonomic.zone ipv4: 94.130.105.60 state: present diff --git a/library/gandi_dns.py b/library/gandi_dns.py index 90ea1c9..0ac1112 100644 --- a/library/gandi_dns.py +++ b/library/gandi_dns.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import json +import os import traceback from subprocess import CalledProcessError, check_output @@ -28,13 +29,13 @@ options: description: The IP v4 address that the domain refers to. type: str required: true - rest_api_key: + gandi_rest_token: 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: true + required: false state: description: - The desired instance state. @@ -48,7 +49,6 @@ options: EXAMPLES = """ - name: Create a new Gandi DNS entry gandi_dns: - rest_api_key: "{{ lookup('env', 'LEXICON_GANDI_AUTH_TOKEN') }}" domain: foobar.autonomic.zone ipv4: 192.168.1.2 state: present @@ -64,30 +64,46 @@ except ImportError: 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 + + def retrieve_domain_info(module): """Retrieve all information about a specific domain.""" + domain = module.params["domain"] + env = get_env() + try: return json.loads( check_output( - [ - "lexicon", - "gandi", - "list", - module.params["domain"], - "A", - "--output", - "JSON", - ] + ["lexicon", "gandi", "list", domain, "A", "--output", "JSON"], + env=env, ) ) - except CalledProcessError as exception: - module.fail_json( - msg="Unable to retrieve domain info. Saw: %s" % str(exception) - ) + except CalledProcessError: + module.fail_json(msg=error_msg(domain)) def create_domain(module): """Create a new DNS entry.""" + domain = module.params["domain"] + ipv4 = module.params["ipv4"] + env = get_env() + try: return json.loads( check_output( @@ -95,25 +111,28 @@ def create_domain(module): "lexicon", "gandi", "create", - module.params["domain"], + domain, "A", "--name", - module.params["domain"], + domain, "--content", - module.params["ipv4"], + ipv4, "--output", "JSON", - ] + ], + env=env, ) ) - except Exception as exception: - module.fail_json( - msg="Unable to create domain entry. Saw: %s" % str(exception) - ) + except Exception: + module.fail_json(msg=error_msg(domain)) def delete_domain(module): """Delete an existing DNS entry.""" + domain = module.params["domain"] + ipv4 = module.params["ipv4"] + env = get_env() + try: return json.loads( check_output( @@ -121,59 +140,58 @@ def delete_domain(module): "lexicon", "gandi", "delete", - module.params["domain"], + domain, "A", "--name", - module.params["domain"], + domain, "--content", - module.params["ipv4"], + ipv4, "--output", "JSON", - ] + ], + env=env, ) ) - except Exception as exception: - module.fail_json( - msg="Unable to delete domain entry. Saw: %s" % str(exception) - ) + except Exception: + module.fail_json(msg=error_msg(domain)) def main(): """Module entrypoint.""" module = AnsibleModule( argument_spec=dict( - domain=dict(type='str', required=True), - ipv4=dict(type='str', required=True), + domain=dict(type="str", required=True), + ipv4=dict(type="str", required=True), state=dict( - type='str', required=True, choices=['present', 'absent'] + type="str", required=True, choices=["present", "absent"] ), - rest_api_key=dict( - type='str', - required=True, + gandi_rest_token=dict( + type="str", + required=False, no_log=True, - fallback=(env_fallback, ['LEXICON_GANDI_AUTH_TOKEN']), + fallback=(env_fallback, ["LEXICON_GANDI_AUTH_TOKEN"]), ), ), supports_check_mode=False, - required_together=(['domain', 'ipv4']), + required_together=(["domain", "ipv4"]), ) if not HAS_DNS_LEXICON_DEPENDENCY: - msg = missing_required_lib('lexicon') + msg = missing_required_lib("lexicon") 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 + existing_domain = module.params["domain"] in [ + domain["name"] for domain in domains ] - if module.params['state'] == 'present': + if module.params["state"] == "present": if existing_domain: module.exit_json(changed=False) create_domain(module) module.exit_json(changed=True) - if module.params['state'] == 'absent': + if module.params["state"] == "absent": if not existing_domain: module.exit_json(changed=False) delete_domain(module) diff --git a/play.yml b/play.yml new file mode 100644 index 0000000..02f1e67 --- /dev/null +++ b/play.yml @@ -0,0 +1,10 @@ +--- +- hosts: localhost + gather_facts: false + connection: local + tasks: + - name: Create foobar.autonomic.zone + gandi_dns: + domain: foobar.autonomic.zone + ipv4: 94.130.105.60 + state: absent diff --git a/pyproject.toml b/pyproject.toml index 60c158d..969d1ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,5 +9,4 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 80 target-version = ["py38"] -skip-string-normalization = true include = '\.pyi?$' diff --git a/test/conftest.py b/test/conftest.py index 4a953ee..c8610bc 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -5,5 +5,5 @@ from ansible.module_utils._text import to_bytes def set_module_args(args): - args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + args = json.dumps({"ANSIBLE_MODULE_ARGS": args}) basic._ANSIBLE_ARGS = to_bytes(args) diff --git a/test/test_gandi_dns.py b/test/test_gandi_dns.py index 442f2d3..dc44330 100644 --- a/test/test_gandi_dns.py +++ b/test/test_gandi_dns.py @@ -1,6 +1,6 @@ import pytest -gandi_cli = pytest.importorskip('lexicon') +gandi_cli = pytest.importorskip("lexicon") def test_TODO():