diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1576ce0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +plugins/action/__pycache__/opnsense_unbound_override_alias.cpython-311.pyc diff --git a/plugins/action/opnsense_unbound_override_alias.py b/plugins/action/opnsense_unbound_override_alias.py new file mode 100644 index 0000000..230cbb6 --- /dev/null +++ b/plugins/action/opnsense_unbound_override_alias.py @@ -0,0 +1,87 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action import ActionBase +import requests + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + if task_vars is None: + task_vars = {} + + # Récupérer les arguments de la tâche + module_args = self._task.args.copy() + + # Valider les arguments + if 'opnsense_url' not in module_args: + return {'failed': True, 'msg': 'The "opnsense_url" argument is mandatory.'} + if 'api_key' not in module_args: + return {'failed': True, 'msg': 'The "api_key" argument is mandatory.'} + if 'api_secret' not in module_args: + return {'failed': True, 'msg': 'The "api_secret" argument is mandatory.'} + if 'override_id' not in module_args: + return {'failed': True, 'msg': 'The "override_id" argument is mandatory.'} + if 'alias_host' not in module_args: + return {'failed': True, 'msg': 'The "alias_value" argument is mandatory.'} + if 'alias_domain' not in module_args: + return {'failed': True, 'msg': 'The "alias_domain" argument is mandatory.'} + + opnsense_url = module_args['opnsense_url'] + api_auth = (module_args['api_key'], module_args['api_secret']) + override_id = module_args['override_id'] + alias_host = module_args['alias_host'] + alias_domain = module_args['alias_domain'] + state = module_args.get('state', 'present') + + base_url = f'{opnsense_url}/api/unbound/settings' + + try: + # Check if override exist + response = requests.get(f'{base_url}/getHostOverride/{override_id}', auth=api_auth) + if response.status_code != 200 or not response.json(): + return {'failed': True, 'msg': f'Fail to fetch override info'} + + # Seach host alias + response = requests.post(f'{base_url}/searchHostAlias/{override_id}', auth=api_auth, json= {'host': override_id, 'searchPhrase': alias_host}) + if response.status_code != 200 : + return {'failed': True, 'msg': f'Fail to fetch Alias list', 'status_code': response.status_code} + json = response.json() + finded = None + if json.get('rowCount', 0) > 0: + # We have result, check if host-domain pair exist + for row in json.get('rows', []): + if row['hostname'] == alias_host and row['domain'] == alias_domain: + finded = row.copy() + + if (state == "present" and finded) or (state == "absent" and not finded): + print('ok') + return {'changed': False} + elif state == "present": + if self._play_context.check_mode: + return {'changed': True} + body = { + "alias": { + "description": "", + "domain": alias_domain, + "enabled": "1", + "host": override_id, + "hostname": alias_host, + } + } + response = requests.post(f'{base_url}/addHostAlias/', auth=api_auth, json=body) + if response.status_code != 200 : + return {'failed': True, 'msg': f'Fail create Alias', 'status_code': response.status_code, 'body': response.json()} + return {'changed': True, 'api_response': response.json()} + elif state == "absent": + if self._play_context.check_mode: + return {'changed': True} + + response = requests.post(f'{base_url}/delHostAlias/{finded["uuid"]}', auth=api_auth) + if response.status_code != 200 : + return {'failed': True, 'msg': f'Fail del Alias', 'status_code': response.status_code, 'body': response.json()} + return {'changed': True, 'api_response': response.json()} + except requests.exceptions.RequestException as e: + return {'failed': True, 'msg': f'Error durring API request : {str(e)}'} + diff --git a/plugins/action/opnsense_unbound_override_reconfigure.py b/plugins/action/opnsense_unbound_override_reconfigure.py new file mode 100644 index 0000000..e6b2584 --- /dev/null +++ b/plugins/action/opnsense_unbound_override_reconfigure.py @@ -0,0 +1,39 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action import ActionBase +import requests + + +class ActionModule(ActionBase): + + def run(self, tmp=None, task_vars=None): + if task_vars is None: + task_vars = {} + + # Récupérer les arguments de la tâche + module_args = self._task.args.copy() + + # Valider les arguments + if 'opnsense_url' not in module_args: + return {'failed': True, 'msg': 'The "opnsense_url" argument is mandatory.'} + if 'api_key' not in module_args: + return {'failed': True, 'msg': 'The "api_key" argument is mandatory.'} + if 'api_secret' not in module_args: + return {'failed': True, 'msg': 'The "api_secret" argument is mandatory.'} + + opnsense_url = module_args['opnsense_url'] + api_auth = (module_args['api_key'], module_args['api_secret']) + + base_url = f'{opnsense_url}/api/unbound/service/reconfigure' + + try: + if self._play_context.check_mode: + return {'changed': True} + response = requests.post(base_url, auth=api_auth) + if response.status_code != 200 : + return {'failed': True, 'msg': f'Fail apply host override change', 'status_code': response.status_code, 'body': response.json()} + return {'changed': True, 'api_response': response.json()} + except requests.exceptions.RequestException as e: + return {'failed': True, 'msg': f'Error durring API request : {str(e)}'} + diff --git a/plugins/modules/opnsense_unbound_override_alias.py b/plugins/modules/opnsense_unbound_override_alias.py new file mode 100644 index 0000000..da91a1e --- /dev/null +++ b/plugins/modules/opnsense_unbound_override_alias.py @@ -0,0 +1,101 @@ +DOCUMENTATION = ''' +--- +module: opnsense_dns_alias +short_description: Ansible action plugin for managing DNS aliases in OPNsense. +description: + - This Ansible action plugin interacts with the OPNsense API to manage DNS aliases. +version_added: "2.9" +requirements: + - Ansible 2.9 or later + - Python 2.7 or later + - The `requests` library for Python (`pip install requests`) +options: + opnsense_url: + description: + - The URL of the OPNsense instance. + required: true + type: str + attributes: + - configurable + api_key: + description: + - The API key for authentication. + required: true + type: str + attributes: + - no_log + api_secret: + description: + - The API secret for authentication. + required: true + type: str + attributes: + - no_log + override_id: + description: + - The ID of the host override. + required: true + type: int + alias_host: + description: + - The hostname for the alias. + required: true + type: str + alias_domain: + description: + - The domain for the alias. + required: true + type: str + state: + description: + - The desired state of the DNS alias. + default: "present" + choices: ["present", "absent"] + type: str +''' + +EXAMPLES = ''' +- name: Add DNS alias + opnsense_dns_alias: + opnsense_url: http://your-opnsense-ip + api_key: your-api-key + api_secret: your-api-secret + override_id: 123 + alias_host: alias-host + alias_domain: alias-domain + state: present + + register: result + +- name: Remove DNS alias + opnsense_dns_alias: + opnsense_url: http://your-opnsense-ip + api_key: your-api-key + api_secret: your-api-secret + override_id: 123 + alias_host: alias-host + alias_domain: alias-domain + state: absent + register: result +''' + +RETURN = ''' +changed: + description: Indicates whether the DNS alias was changed. + type: bool +api_response: + description: The response from the OPNsense API. + type: dict +failed: + description: Indicates whether the task failed. + type: bool +msg: + description: An error message if the task failed. + type: str +status_code: + description: The HTTP status code of the API response. + type: int +body: + description: The JSON body of the API response. + type: dict +''' \ No newline at end of file diff --git a/plugins/modules/opnsense_unbound_override_reconfigure.py b/plugins/modules/opnsense_unbound_override_reconfigure.py new file mode 100644 index 0000000..0c8e43a --- /dev/null +++ b/plugins/modules/opnsense_unbound_override_reconfigure.py @@ -0,0 +1,65 @@ +DOCUMENTATION = ''' +--- +module: opnsense_reconfigure_unbound +short_description: Ansible action plugin for triggering a reconfiguration of Unbound service in OPNsense. +description: + - This Ansible action plugin interacts with the OPNsense API to trigger a reconfiguration of the Unbound service. +version_added: "2.9" +requirements: + - Ansible 2.9 or later + - Python 2.7 or later + - The `requests` library for Python (`pip install requests`) +options: + opnsense_url: + description: + - The URL of the OPNsense instance. + required: true + type: str + attributes: + - configurable + api_key: + description: + - The API key for authentication. + required: true + type: str + attributes: + - no_log + api_secret: + description: + - The API secret for authentication. + required: true + type: str + attributes: + - no_log +''' + +EXAMPLES = ''' +- name: Trigger Unbound reconfiguration + opnsense_reconfigure_unbound: + opnsense_url: http://your-opnsense-ip + api_key: your-api-key + api_secret: your-api-secret + check_mode: false + register: result +''' + +RETURN = ''' +changed: + description: Indicates whether the Unbound service was reconfigured. + type: bool +api_response: + description: The response from the OPNsense API. + type: dict +failed: + description: Indicates whether the task failed. + type: bool +msg: + description: An error message if the task failed. + type: str +status_code: + description: The HTTP status code of the API response. + type: int +body: + description: The JSON body of the API response. + type: dict +'''