15 Commits

Author SHA1 Message Date
bdeed4cd46 Add mirror note
All checks were successful
continuous-integration/drone/push Build is passing
2020-04-09 08:30:30 +02:00
5e1ebc6329 Add required version for crypto
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 14:50:57 +02:00
767316125d Pass in the right env var too
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 14:46:16 +02:00
995592a555 Add example and drop non-existant extra
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 14:41:47 +02:00
f1abb8cb37 Remove import not available in older Ansible
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 14:19:19 +02:00
6544f2acc8 Bump version (forgot to include in 0.0.3 tag) 2020-03-29 14:17:30 +02:00
bebccfab99 Pass tar.gz file
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 10:40:42 +02:00
ff000ed5b1 Bump version
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 10:39:33 +02:00
f4a49b5843 Add missing role folders
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 10:37:35 +02:00
9e1b4bb9e6 Bump package version
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 09:14:06 +02:00
afc4b987a7 Bump version 2020-03-29 09:13:56 +02:00
35d665a31a Clarify argument usage
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 09:13:37 +02:00
05a5824225 Fix grammar
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 09:12:46 +02:00
45463d4e54 Clarify env var usage
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 09:12:01 +02:00
d430e3ffbb Improve env var management for LEXICON vars
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-29 09:07:36 +02:00
10 changed files with 127 additions and 58 deletions

View File

@ -12,9 +12,24 @@ Ansible libraries for managing Gandi resources.
gather_facts: false
connection: local
tasks:
- name: Prepare Python dependencies
become: true
apt:
name: python3-pip
state: present
- name: Install dns-lexicon system wide
become: true
pip:
name: "{{ item }}"
executable: /usr/bin/pip3
with_items:
- dns-lexicon==3.3.19
- cryptography==2.8
- 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
@ -32,7 +47,7 @@ Ansible libraries for managing Gandi resources.
- [dns-lexicon >= 3.3.19](https://pypi.org/project/dns-lexicon/) (if using `gandi_dns` module)
```bash
$ pip install ansible==2.6.9 "dns-lexicon[gandi]==3.3.19"
$ pip install ansible==2.6.9 dns-lexicon==3.3.19
```
These should be present on the localhost where you run Ansible.
@ -53,16 +68,27 @@ You can test that everything is working by running the following.
$ lexicon gandi list autonomic.zone A
```
The `gandi_dns` module will provide the `PROVIDER` and
`LEXICON_GANDI_API_PROTOCOL` environment variables internally so you only need
to pass `LEXICON_GANDI_AUTH_TOKEN` as the `gandi_rest_token` argument to the
task or expose it in the environment and it will be picked up.
## Usage
Include an entry in your `requirements.yml` like so.
```yaml
- src: https://git.autonomic.zone/autonomic-cooperative/autonomic.gandi
version: 0.0.1
- src: https://git.autonomic.zone/autonomic-cooperative/autonomic.gandi/archive/0.0.5.tar.gz
name: autonomic.gandi
```
See the [releases](https://git.autonomic.zone/autonomic-cooperative/autonomic.gandi/releases) for which is the latest version.
Then make sure to download the role with `ansible-galaxy install -r requirements.yml`.
Note, we also keep a mirror on [git.coop](https://git.coop) for when we run internal Gitea upgrades.
```
- src: https://git.coop/decentral1se/autonomic.gandi/-/archive/0.0.5/autonomic.gandi-0.0.5.tar.gz
name: autonomic.gandi
```

1
defaults/main.yml Normal file
View File

@ -0,0 +1 @@
---

View File

@ -1,14 +1,11 @@
#!/usr/bin/env python3
import json
import os
import traceback
from subprocess import CalledProcessError, check_output
from ansible.module_utils.basic import (
AnsibleModule,
env_fallback,
missing_required_lib,
)
from ansible.module_utils.basic import AnsibleModule, env_fallback
DOCUMENTATION = """
---
@ -28,13 +25,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 +45,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 +60,47 @@ 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(module):
"""Build environment for running command-line commands."""
env = os.environ.copy()
env["PROVIDER"] = "gandi"
env["LEXICON_GANDI_API_PROTOCOL"] = "rest"
env["LEXICON_GANDI_AUTH_TOKEN"] = module.params["gandi_rest_token"]
return env
def retrieve_domain_info(module):
"""Retrieve all information about a specific domain."""
domain = module.params["domain"]
env = get_env(module)
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(module)
try:
return json.loads(
check_output(
@ -95,25 +108,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(module)
try:
return json.loads(
check_output(
@ -121,59 +137,62 @@ 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 dns-lexicon, please run apt "
"install -y python3-lexicon or install it "
" using the Ansible `apt` module."
)
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)

13
meta/main.yml Normal file
View File

@ -0,0 +1,13 @@
---
dependencies: []
galaxy_info:
author: autonomic
description: Ansible libraries for managing Gandi resources.
company: Autonomic
license: GPLv
min_ansible_version: 2.9.6
platforms:
- name: Debian
versions:
- buster

10
play.yml Normal file
View File

@ -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

View File

@ -9,5 +9,4 @@ build-backend = "setuptools.build_meta"
[tool.black]
line-length = 80
target-version = ["py38"]
skip-string-normalization = true
include = '\.pyi?$'

View File

@ -13,7 +13,7 @@ include_trailing_comma = True
[metadata]
name = autonomic.gandi
author = decentral1se
version = 0.0.1
version = 0.0.5
[options]
packages = find:

1
tasks/main.yml Normal file
View File

@ -0,0 +1 @@
---

View File

@ -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)

View File

@ -1,6 +1,6 @@
import pytest
gandi_cli = pytest.importorskip('lexicon')
gandi_cli = pytest.importorskip("lexicon")
def test_TODO():