From 3ae0d7948e307fe300e2a952c071b4e59420bc66 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Wed, 25 Sep 2024 12:16:12 +0000 Subject: [PATCH 1/5] Add modules for dhcrelay --- docs/source/modules/dhcrelay_destination.rst | 82 +++++++++++ docs/source/modules/dhcrelay_relay.rst | 83 +++++++++++ meta/runtime.yml | 4 + .../module_utils/main/dhcrelay_destination.py | 42 ++++++ plugins/module_utils/main/dhcrelay_relay.py | 58 ++++++++ plugins/modules/dhcrelay_destination.py | 66 +++++++++ plugins/modules/dhcrelay_relay.py | 73 ++++++++++ plugins/modules/list.py | 10 +- scripts/test.sh | 2 + tests/dhcrelay_destination.yml | 115 +++++++++++++++ tests/dhcrelay_relay.yml | 137 ++++++++++++++++++ 11 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 docs/source/modules/dhcrelay_destination.rst create mode 100644 docs/source/modules/dhcrelay_relay.rst create mode 100644 plugins/module_utils/main/dhcrelay_destination.py create mode 100644 plugins/module_utils/main/dhcrelay_relay.py create mode 100644 plugins/modules/dhcrelay_destination.py create mode 100644 plugins/modules/dhcrelay_relay.py create mode 100644 tests/dhcrelay_destination.yml create mode 100644 tests/dhcrelay_relay.yml diff --git a/docs/source/modules/dhcrelay_destination.rst b/docs/source/modules/dhcrelay_destination.rst new file mode 100644 index 0000000..227885b --- /dev/null +++ b/docs/source/modules/dhcrelay_destination.rst @@ -0,0 +1,82 @@ +.. _modules_dhcrelay_destination: + +.. include:: ../_include/head.rst + +============================= +DHCRelay - Destinations +============================= + +**STATE**: stable + +**TESTS**: `Playbook `_ + +**API Docs**: `Core - DHCRelay `_ + +**Service Docs**: `DHCRelay `_ + + +Definition +********** + +.. csv-table:: Definition + :header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment" + :widths: 15 10 10 10 10 45 + + "name","string","true","","\-","Unique name for this relay destination" + "server","list of strings","true","\-","\-","List of server IP addresses to relay DHCP requests to" + "reload","boolean","false","true","\-", .. include:: ../_include/param_reload.rst + +.. include:: ../_include/param_basic.rst + +Info +**** + +This module manages DHCRelay destinations. A destination can contain multiple IP addresses. + + +Examples +******** + +.. code-block:: yaml + + - hosts: localhost + gather_facts: no + module_defaults: + group/ansibleguy.opnsense.all: + firewall: 'opnsense.template.ansibleguy.net' + api_credential_file: '/home/guy/.secret/opn.key' + + ansibleguy.opnsense.list: + target: 'dhcrelay_destination' + + tasks: + - name: Example + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + server: + - '192.168.0.1' + # state: 'present' + # reload: true + # debug: false + + - name: Adding + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + server: + - '192.168.0.1' + + - name: Removing + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + server: + - '192.168.0.1' + state: 'absent' + + - name: Listing + ansibleguy.opnsense.list: + # target: 'dhcrelay_destination' + register: existing_entries + + - name: Printing dhcrelay destinations + ansible.builtin.debug: + var: existing_entries.data diff --git a/docs/source/modules/dhcrelay_relay.rst b/docs/source/modules/dhcrelay_relay.rst new file mode 100644 index 0000000..3a5c2c4 --- /dev/null +++ b/docs/source/modules/dhcrelay_relay.rst @@ -0,0 +1,83 @@ +.. _modules_dhcrelay_relay: + +.. include:: ../_include/head.rst + +============================= +DHCRelay - Relay +============================= + +**STATE**: stable + +**TESTS**: `Playbook `_ + +**API Docs**: `Core - DHCRelay `_ + +**Service Docs**: `DHCRelay `_ + + +Definition +********** + +.. csv-table:: Definition + :header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment" + :widths: 15 10 10 10 10 45 + + "enabled","boolean","false","false","\-","Enable or disable this relay" + "interface","string","true","","i, int"," The interface to relay DHCP requests from" + "destination","string","true","\-","dest"," The destination server group to relay DHCP requests to" + "agent_info","boolean","false","false","\-","Add the relay agent information option" + "reload","boolean","false","true","\-", .. include:: ../_include/param_reload.rst + +.. include:: ../_include/param_basic.rst + +Info +**** + +This module manages DHCRelay relays. Each interface can be assigned a single relay. + + +Examples +******** + +.. code-block:: yaml + + - hosts: localhost + gather_facts: no + module_defaults: + group/ansibleguy.opnsense.all: + firewall: 'opnsense.template.ansibleguy.net' + api_credential_file: '/home/guy/.secret/opn.key' + + ansibleguy.opnsense.list: + target: 'dhcrelay_relay' + + tasks: + - name: Example + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: mydhcp + # enabled: false + # agent_info: false + # state: 'present' + # reload: true + # debug: false + + - name: Adding + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: mydhcp + + - name: Removing + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: mydhcp + state: 'absent' + + - name: Listing + ansibleguy.opnsense.list: + # target: 'dhcrelay_relay' + register: existing_entries + + - name: Printing dhcrelay relays + ansible.builtin.debug: + var: existing_entries.data diff --git a/meta/runtime.yml b/meta/runtime.yml index 2306884..b4ac572 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -119,6 +119,9 @@ action_groups: - ansibleguy.opnsense.openvpn_client_override - ansibleguy.opnsense.openvpn_client_template - ansibleguy.opnsense.openvpn_client_export + dhcrelay: + - ansibleguy.opnsense.dhcrelay_destination + - ansibleguy.opnsense.dhcrelay_relay all: - metadata: extend_group: @@ -140,6 +143,7 @@ action_groups: - ansibleguy.opnsense.system - ansibleguy.opnsense.ids - ansibleguy.opnsense.openvpn + - ansibleguy.opnsense.dhcrelay plugin_routing: modules: diff --git a/plugins/module_utils/main/dhcrelay_destination.py b/plugins/module_utils/main/dhcrelay_destination.py new file mode 100644 index 0000000..7d5f631 --- /dev/null +++ b/plugins/module_utils/main/dhcrelay_destination.py @@ -0,0 +1,42 @@ +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.api import \ + Session +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \ + is_unset +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.cls import BaseModule + + +class DhcRelayDestination(BaseModule): + FIELD_ID = 'name' + CMDS = { + 'add': 'addDest', + 'del': 'delDest', + 'set': 'setDest', + 'search': 'get', + } + API_KEY_PATH = 'dhcrelay.destinations' + API_KEY_PATH_REQ = 'destination' + API_MOD = 'dhcrelay' + API_CONT = 'settings' + API_CONT_REL = 'service' + API_CMD_REL = 'reconfigure' + FIELDS_CHANGE = ['server'] + FIELDS_ALL = [FIELD_ID] + FIELDS_ALL.extend(FIELDS_CHANGE) + FIELDS_TYPING = { + 'list': ['server'], + } + EXIST_ATTR = 'destination' + + def __init__(self, module: AnsibleModule, result: dict, session: Session = None): + BaseModule.__init__(self=self, m=module, r=result, s=session) + self.destination = {} + + def check(self) -> None: + + if self.p['state'] == 'present': + if is_unset(self.p['server']): + self.m.fail_json("You need to provide list of 'server' to create a dhcrelay_destination!") + + self._base_check() diff --git a/plugins/module_utils/main/dhcrelay_relay.py b/plugins/module_utils/main/dhcrelay_relay.py new file mode 100644 index 0000000..9430189 --- /dev/null +++ b/plugins/module_utils/main/dhcrelay_relay.py @@ -0,0 +1,58 @@ +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.api import \ + Session +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \ + is_unset +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.cls import BaseModule + + +class DhcRelayRelay(BaseModule): + FIELD_ID = 'interface' + CMDS = { + 'add': 'addRelay', + 'del': 'delRelay', + 'set': 'setRelay', + 'search': 'get', + 'detail': 'getRelay' + } + API_KEY_PATH = 'dhcrelay.relays' + API_KEY_PATH_REQ = 'relay' + API_MOD = 'dhcrelay' + API_CONT = 'settings' + API_CONT_REL = 'service' + API_CMD_REL = 'reconfigure' + FIELDS_CHANGE = ['enabled', 'destination', 'agent_info'] + FIELDS_ALL = [FIELD_ID] + FIELDS_ALL.extend(FIELDS_CHANGE) + FIELDS_VALUE_MAPPING = {} + FIELDS_TYPING = { + 'select': ['interface'], + 'select_opt_list': ['destination'], + 'bool': ['enabled', 'agent_info'] + } + EXIST_ATTR = 'relay' + + def __init__(self, module: AnsibleModule, result: dict, session: Session = None): + BaseModule.__init__(self=self, m=module, r=result, s=session) + self.relay = {} + + + def check(self) -> None: + if self.p['state'] == 'present': + if is_unset(self.p['destination']): + self.m.fail_json("You need to provide a 'destination' to create a dhcrelay_relay!") + + if self.p['state'] == 'present': + template = self.s.get({ + **self.call_cnf, + 'command': self.CMDS['detail'], + }) + + if template['relay']['destination']: + self.FIELDS_VALUE_MAPPING['destination'] = { + v['value']:k + for k,v in template['relay']['destination'].items() + } + + self._base_check() diff --git a/plugins/modules/dhcrelay_destination.py b/plugins/modules/dhcrelay_destination.py new file mode 100644 index 0000000..972eabf --- /dev/null +++ b/plugins/modules/dhcrelay_destination.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (C) 2024, AnsibleGuy +# GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) + +# see: https://docs.opnsense.org/development/api/core/dhcrelay.html + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.handler import \ + module_dependency_error, MODULE_EXCEPTIONS + +try: + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.wrapper import module_wrapper + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.defaults.main import \ + OPN_MOD_ARGS, STATE_ONLY_MOD_ARG, RELOAD_MOD_ARG + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.dhcrelay_destination import \ + DhcRelayDestination + +except MODULE_EXCEPTIONS: + module_dependency_error() + + +# DOCUMENTATION = 'https://opnsense.ansibleguy.net/en/latest/modules/dhcrelay_destination.html' +# EXAMPLES = 'https://opnsense.ansibleguy.net/en/latest/modules/dhcrelay_destination.html' + + +def run_module(): + module_args = dict( + name=dict( + type='str', required=True, + description='A unique name for this relay destination.', + ), + server=dict( + type='list', elements='str', required=False, + description='A list of server IP addresses to relay DHCP requests to.' + ), + **RELOAD_MOD_ARG, + **STATE_ONLY_MOD_ARG, + **OPN_MOD_ARGS, + ) + + result = dict( + changed=False, + diff={ + 'before': {}, + 'after': {}, + } + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + ) + + module_wrapper(DhcRelayDestination(module=module, result=result)) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/dhcrelay_relay.py b/plugins/modules/dhcrelay_relay.py new file mode 100644 index 0000000..8bb0611 --- /dev/null +++ b/plugins/modules/dhcrelay_relay.py @@ -0,0 +1,73 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (C) 2024, AnsibleGuy +# GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) + +# see: https://docs.opnsense.org/development/api/core/dhcrelay.html + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.handler import \ + module_dependency_error, MODULE_EXCEPTIONS + +try: + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.wrapper import module_wrapper + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.defaults.main import \ + OPN_MOD_ARGS, STATE_ONLY_MOD_ARG, RELOAD_MOD_ARG + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.dhcrelay_relay import DhcRelayRelay + +except MODULE_EXCEPTIONS: + module_dependency_error() + + +# DOCUMENTATION = 'https://opnsense.ansibleguy.net/en/latest/modules/dhcrelay_relay.html' +# EXAMPLES = 'https://opnsense.ansibleguy.net/en/latest/modules/dhcrelay_relay.html' + + +def run_module(): + module_args = dict( + enabled=dict( + type='bool', default=False, + description='Enable or disable this relay.', + ), + interface=dict( + type='str', required=True, aliases=['i', 'int'], + description='The interface to relay DHCP requests from. ' + ), + destination=dict( + type='str', required=False, aliases=['dest'], + description='The uuid of the destination server group to relay DHCP requests to.' + ), + agent_info=dict( + type='bool', default=False, + description='Add the relay agent information option.', + ), + **RELOAD_MOD_ARG, + **STATE_ONLY_MOD_ARG, + **OPN_MOD_ARGS, + ) + + result = dict( + changed=False, + diff={ + 'before': {}, + 'after': {}, + } + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + ) + + module_wrapper(DhcRelayRelay(module=module, result=result)) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/list.py b/plugins/modules/list.py index dd8d1d8..802ca18 100644 --- a/plugins/modules/list.py +++ b/plugins/modules/list.py @@ -35,7 +35,7 @@ 'webproxy_acl', 'webproxy_icap', 'webproxy_auth', 'nginx_upstream_server', 'ipsec_connection', 'ipsec_pool', 'ipsec_child', 'ipsec_vti', 'ipsec_auth_local', 'ipsec_auth_remote', 'frr_general', 'unbound_general', 'unbound_acl', 'ids_general', 'ids_policy', 'ids_rule', 'ids_ruleset', 'ids_user_rule', 'ids_policy_rule', - 'openvpn_instance', 'openvpn_static_key', 'openvpn_client_override', + 'openvpn_instance', 'openvpn_static_key', 'openvpn_client_override', 'dhcrelay_destination', 'dhcrelay_relay', ] @@ -378,6 +378,14 @@ def run_module(): from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.openvpn_client_override import \ Override as Target_Obj + elif target == 'dhcrelay_destination': + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.dhcrelay_destination import \ + DhcRelayDestination as Target_Obj + + elif target == 'dhcrelay_relay': + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.dhcrelay_relay import \ + DhcRelayRelay as Target_Obj + except AttributeError: module_dependency_error() diff --git a/scripts/test.sh b/scripts/test.sh index 40ccc94..12d177d 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -149,6 +149,8 @@ run_test 'nginx_general' 1 run_test 'nginx_upstream_server' 1 run_test 'system' 1 run_test 'package' 1 +run_test 'dhcrelay_destination' 1 +run_test 'dhcrelay_relay' 1 echo '' echo '##############################' diff --git a/tests/dhcrelay_destination.yml b/tests/dhcrelay_destination.yml new file mode 100644 index 0000000..2159baf --- /dev/null +++ b/tests/dhcrelay_destination.yml @@ -0,0 +1,115 @@ +--- + +# todo: test default matching + +- name: Testing DHCRelay Destination + hosts: localhost + gather_facts: no + module_defaults: + group/ansibleguy.opnsense.all: + firewall: "{{ lookup('ansible.builtin.env', 'TEST_FIREWALL') }}" + api_credential_file: "{{ lookup('ansible.builtin.env', 'TEST_API_KEY') }}" + ssl_verify: false + + ansibleguy.opnsense.list: + target: 'dhcrelay_destination' + + tasks: + - name: Listing + ansibleguy.opnsense.list: + register: opn1 + failed_when: > + 'data' not in opn1 or + opn1.data | length != 0 + + - name: Removing - does not exist + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + state: 'absent' + reload: false + register: opn2 + failed_when: > + opn2.failed or + opn2.changed + + - name: Adding - failing because of invalid values + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + server: '{{ item }}' + reload: false + register: opn_fail1 + failed_when: not opn_fail1.failed + loop: + - ['dhcp'] + - ['172.0.0'] + when: not ansible_check_mode + + - name: Adding 1 + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + server: + - '192.168.254.254' + reload: false # speed + register: opn3 + failed_when: > + opn3.failed or + not opn3.changed + + - name: Adding 2 + ansibleguy.opnsense.dhcrelay_destination: + name: 'myotherdhcp' + server: + - '192.168.254.252' + - '192.168.254.253' + reload: false # speed + register: opn4 + failed_when: > + opn4.failed or + not opn4.changed + + - name: Adding 2 - nothing changed + ansibleguy.opnsense.dhcrelay_destination: + name: 'myotherdhcp' + server: + - '192.168.254.252' + - '192.168.254.253' + reload: false # speed + register: opn5 + failed_when: > + opn5.failed or + opn5.changed + when: not ansible_check_mode + + - name: Removing 2 + ansibleguy.opnsense.dhcrelay_destination: + name: 'myotherdhcp' + state: 'absent' + reload: false # speed + register: opn6 + failed_when: > + opn6.failed or + not opn6.changed + when: not ansible_check_mode + + - name: Listing + ansibleguy.opnsense.list: + register: opn7 + failed_when: > + 'data' not in opn7 or + opn7.data | length != 1 + when: not ansible_check_mode + + - name: Cleanup + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + state: 'absent' + reload: false # speed + when: not ansible_check_mode + + - name: Listing + ansibleguy.opnsense.list: + register: opn8 + failed_when: > + 'data' not in opn8 or + opn8.data | length != 0 + when: not ansible_check_mode diff --git a/tests/dhcrelay_relay.yml b/tests/dhcrelay_relay.yml new file mode 100644 index 0000000..c1f0981 --- /dev/null +++ b/tests/dhcrelay_relay.yml @@ -0,0 +1,137 @@ +--- +- name: Testing DHCRelay Relay + hosts: localhost + gather_facts: no + module_defaults: + group/ansibleguy.opnsense.all: + firewall: "{{ lookup('ansible.builtin.env', 'TEST_FIREWALL') }}" + api_credential_file: "{{ lookup('ansible.builtin.env', 'TEST_API_KEY') }}" + ssl_verify: false + + ansibleguy.opnsense.list: + target: 'dhcrelay_relay' + + tasks: + - name: Listing + ansibleguy.opnsense.list: + register: opn1 + failed_when: > + 'data' not in opn1 or + opn1.data | length != 0 + + - name: Removing - does not exist + ansibleguy.opnsense.dhcrelay_relay: + interface: 'DOESNOTEXIST' + state: 'absent' + reload: false + register: opn2 + failed_when: > + opn2.failed or + opn2.changed + + - name: Adding - failing because of invalid interface + ansibleguy.opnsense.dhcrelay_relay: + interface: 'DOESNOTEXIST' + server: 'mydhcp' + reload: false + register: opn_fail1 + failed_when: not opn_fail1.failed + when: not ansible_check_mode + + - name: Adding - failing because of invalid destination + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: 'DOESNOTEXIST' + reload: false + register: opn_fail2 + failed_when: not opn_fail2.failed + when: not ansible_check_mode + + - name: Adding destination + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + server: + - '192.168.254.254' + reload: false # speed + when: not ansible_check_mode + + - name: Adding 1 + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: 'mydhcp' + reload: false # speed + register: opn3 + failed_when: > + opn3.failed or + not opn3.changed + + - name: Adding 1 - nothing changed + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: 'mydhcp' + reload: false # speed + debug: true + register: opn4 + failed_when: > + opn4.failed or + opn4.changed + when: not ansible_check_mode + + - name: Enabling 1 + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: 'mydhcp' + enabled: true + reload: false # speed + register: opn5 + failed_when: > + opn5.failed or + not opn5.changed + when: not ansible_check_mode + + - name: Enabling 1 - nothing changed + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + destination: 'mydhcp' + enabled: true + reload: false # speed + register: opn6 + failed_when: > + opn6.failed or + opn6.changed + when: not ansible_check_mode + + - name: Listing + ansibleguy.opnsense.list: + register: opn5 + failed_when: > + 'data' not in opn5 or + opn5.data | length != 1 + when: not ansible_check_mode + + - name: Removing + ansibleguy.opnsense.dhcrelay_relay: + interface: 'lan' + state: 'absent' + reload: false # speed + when: not ansible_check_mode + register: opn6 + failed_when: > + opn6.failed or + not opn6.changed + when: not ansible_check_mode + + - name: Cleanup destination + ansibleguy.opnsense.dhcrelay_destination: + name: 'mydhcp' + state: 'absent' + reload: false # speed + when: not ansible_check_mode + + - name: Listing + ansibleguy.opnsense.list: + register: opn7 + failed_when: > + 'data' not in opn7 or + opn7.data | length != 0 + when: not ansible_check_mode From 36655d9de0803e96dda62847342e7a2879d124b0 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Tue, 1 Oct 2024 09:06:44 +0000 Subject: [PATCH 2/5] Rework dhcrelay_relay for simpler code --- plugins/module_utils/main/dhcrelay_relay.py | 41 +++++++++++---------- tests/dhcrelay_destination.yml | 14 +++---- tests/dhcrelay_relay.yml | 30 ++++++++------- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/plugins/module_utils/main/dhcrelay_relay.py b/plugins/module_utils/main/dhcrelay_relay.py index 9430189..af14006 100644 --- a/plugins/module_utils/main/dhcrelay_relay.py +++ b/plugins/module_utils/main/dhcrelay_relay.py @@ -4,7 +4,7 @@ Session from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \ is_unset -from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.cls import BaseModule +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.cls import BaseModule class DhcRelayRelay(BaseModule): @@ -14,7 +14,7 @@ class DhcRelayRelay(BaseModule): 'del': 'delRelay', 'set': 'setRelay', 'search': 'get', - 'detail': 'getRelay' + 'toggle': 'toggleRelay', } API_KEY_PATH = 'dhcrelay.relays' API_KEY_PATH_REQ = 'relay' @@ -22,37 +22,38 @@ class DhcRelayRelay(BaseModule): API_CONT = 'settings' API_CONT_REL = 'service' API_CMD_REL = 'reconfigure' - FIELDS_CHANGE = ['enabled', 'destination', 'agent_info'] - FIELDS_ALL = [FIELD_ID] + FIELDS_CHANGE = ['destination', 'agent_info'] + FIELDS_ALL = [FIELD_ID, 'enabled'] FIELDS_ALL.extend(FIELDS_CHANGE) - FIELDS_VALUE_MAPPING = {} FIELDS_TYPING = { - 'select': ['interface'], - 'select_opt_list': ['destination'], + 'select': ['interface', 'destination'], 'bool': ['enabled', 'agent_info'] } EXIST_ATTR = 'relay' + SEARCH_ADDITIONAL = { + 'existing_destinations': 'dhcrelay.destinations', + } def __init__(self, module: AnsibleModule, result: dict, session: Session = None): BaseModule.__init__(self=self, m=module, r=result, s=session) self.relay = {} - + self.existing_destinations = None def check(self) -> None: if self.p['state'] == 'present': if is_unset(self.p['destination']): self.m.fail_json("You need to provide a 'destination' to create a dhcrelay_relay!") - if self.p['state'] == 'present': - template = self.s.get({ - **self.call_cnf, - 'command': self.CMDS['detail'], - }) - - if template['relay']['destination']: - self.FIELDS_VALUE_MAPPING['destination'] = { - v['value']:k - for k,v in template['relay']['destination'].items() - } - self._base_check() + + if not is_unset(self.p['destination']) and self.existing_destinations: + for key, values in self.existing_destinations.items(): + if values['name'] == self.p['destination']: + self.p['destination'] = key + break + + def get_existing(self) -> list: + existing = self.b.get_existing() + for relay in existing: + relay['destination'] = self.existing_destinations[relay['destination']]['name'] + return existing diff --git a/tests/dhcrelay_destination.yml b/tests/dhcrelay_destination.yml index 2159baf..c67a588 100644 --- a/tests/dhcrelay_destination.yml +++ b/tests/dhcrelay_destination.yml @@ -24,7 +24,7 @@ - name: Removing - does not exist ansibleguy.opnsense.dhcrelay_destination: - name: 'mydhcp' + name: 'ANSIBLE_TEST_1_1' state: 'absent' reload: false register: opn2 @@ -34,7 +34,7 @@ - name: Adding - failing because of invalid values ansibleguy.opnsense.dhcrelay_destination: - name: 'mydhcp' + name: 'ANSIBLE_TEST_1_1' server: '{{ item }}' reload: false register: opn_fail1 @@ -46,7 +46,7 @@ - name: Adding 1 ansibleguy.opnsense.dhcrelay_destination: - name: 'mydhcp' + name: 'ANSIBLE_TEST_1_1' server: - '192.168.254.254' reload: false # speed @@ -57,7 +57,7 @@ - name: Adding 2 ansibleguy.opnsense.dhcrelay_destination: - name: 'myotherdhcp' + name: 'ANSIBLE_TEST_1_2' server: - '192.168.254.252' - '192.168.254.253' @@ -69,7 +69,7 @@ - name: Adding 2 - nothing changed ansibleguy.opnsense.dhcrelay_destination: - name: 'myotherdhcp' + name: 'ANSIBLE_TEST_1_2' server: - '192.168.254.252' - '192.168.254.253' @@ -82,7 +82,7 @@ - name: Removing 2 ansibleguy.opnsense.dhcrelay_destination: - name: 'myotherdhcp' + name: 'ANSIBLE_TEST_1_2' state: 'absent' reload: false # speed register: opn6 @@ -101,7 +101,7 @@ - name: Cleanup ansibleguy.opnsense.dhcrelay_destination: - name: 'mydhcp' + name: 'ANSIBLE_TEST_1_1' state: 'absent' reload: false # speed when: not ansible_check_mode diff --git a/tests/dhcrelay_relay.yml b/tests/dhcrelay_relay.yml index c1f0981..719faf8 100644 --- a/tests/dhcrelay_relay.yml +++ b/tests/dhcrelay_relay.yml @@ -11,6 +11,9 @@ ansibleguy.opnsense.list: target: 'dhcrelay_relay' + vars: + if_dhcrelay: "{{ lookup('ansible.builtin.env', 'TEST_DHCRELAY_IF') | default('lan', true) }}" + tasks: - name: Listing ansibleguy.opnsense.list: @@ -32,7 +35,7 @@ - name: Adding - failing because of invalid interface ansibleguy.opnsense.dhcrelay_relay: interface: 'DOESNOTEXIST' - server: 'mydhcp' + server: 'ANSIBLE_TEST_1_1' reload: false register: opn_fail1 failed_when: not opn_fail1.failed @@ -40,7 +43,7 @@ - name: Adding - failing because of invalid destination ansibleguy.opnsense.dhcrelay_relay: - interface: 'lan' + interface: '{{ if_dhcrelay }}' destination: 'DOESNOTEXIST' reload: false register: opn_fail2 @@ -49,7 +52,7 @@ - name: Adding destination ansibleguy.opnsense.dhcrelay_destination: - name: 'mydhcp' + name: 'ANSIBLE_TEST_1_1' server: - '192.168.254.254' reload: false # speed @@ -57,8 +60,8 @@ - name: Adding 1 ansibleguy.opnsense.dhcrelay_relay: - interface: 'lan' - destination: 'mydhcp' + interface: '{{ if_dhcrelay }}' + destination: 'ANSIBLE_TEST_1_1' reload: false # speed register: opn3 failed_when: > @@ -67,10 +70,9 @@ - name: Adding 1 - nothing changed ansibleguy.opnsense.dhcrelay_relay: - interface: 'lan' - destination: 'mydhcp' + interface: '{{ if_dhcrelay }}' + destination: 'ANSIBLE_TEST_1_1' reload: false # speed - debug: true register: opn4 failed_when: > opn4.failed or @@ -79,8 +81,8 @@ - name: Enabling 1 ansibleguy.opnsense.dhcrelay_relay: - interface: 'lan' - destination: 'mydhcp' + interface: '{{ if_dhcrelay }}' + destination: 'ANSIBLE_TEST_1_1' enabled: true reload: false # speed register: opn5 @@ -91,8 +93,8 @@ - name: Enabling 1 - nothing changed ansibleguy.opnsense.dhcrelay_relay: - interface: 'lan' - destination: 'mydhcp' + interface: '{{ if_dhcrelay }}' + destination: 'ANSIBLE_TEST_1_1' enabled: true reload: false # speed register: opn6 @@ -111,7 +113,7 @@ - name: Removing ansibleguy.opnsense.dhcrelay_relay: - interface: 'lan' + interface: '{{ if_dhcrelay }}' state: 'absent' reload: false # speed when: not ansible_check_mode @@ -123,7 +125,7 @@ - name: Cleanup destination ansibleguy.opnsense.dhcrelay_destination: - name: 'mydhcp' + name: 'ANSIBLE_TEST_1_1' state: 'absent' reload: false # speed when: not ansible_check_mode From e8db4c8055be9f6081481945182ed3dcd790d45b Mon Sep 17 00:00:00 2001 From: Pascal Rath Date: Sun, 6 Oct 2024 14:05:44 +0200 Subject: [PATCH 3/5] add shortform module-aliases --- docs/source/modules/dhcrelay_destination.rst | 1 + docs/source/modules/dhcrelay_relay.rst | 1 + meta/runtime.yml | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/docs/source/modules/dhcrelay_destination.rst b/docs/source/modules/dhcrelay_destination.rst index 227885b..89cbd24 100644 --- a/docs/source/modules/dhcrelay_destination.rst +++ b/docs/source/modules/dhcrelay_destination.rst @@ -33,6 +33,7 @@ Info This module manages DHCRelay destinations. A destination can contain multiple IP addresses. +Note: You can also use the shortform module name: :code:`ansibleguy.opnsense.dhcrelay_dst` Examples ******** diff --git a/docs/source/modules/dhcrelay_relay.rst b/docs/source/modules/dhcrelay_relay.rst index 3a5c2c4..677ec8b 100644 --- a/docs/source/modules/dhcrelay_relay.rst +++ b/docs/source/modules/dhcrelay_relay.rst @@ -35,6 +35,7 @@ Info This module manages DHCRelay relays. Each interface can be assigned a single relay. +Note: You can also use the shortform module name: :code:`ansibleguy.opnsense.dhcrelay` Examples ******** diff --git a/meta/runtime.yml b/meta/runtime.yml index b4ac572..a8a184b 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -185,3 +185,7 @@ plugin_routing: redirect: ansibleguy.opnsense.gateway rule_if_group: redirect: ansibleguy.opnsense.rule_interface_group + dhcrelay: + redirect: ansibleguy.opnsense.dhcrelay_relay + dhcrelay_dst: + redirect: ansibleguy.opnsense.dhcrelay_destination From e055e3ca293ef0713df8f95c8865a85d69886b1f Mon Sep 17 00:00:00 2001 From: Pascal Rath Date: Sun, 6 Oct 2024 14:06:08 +0200 Subject: [PATCH 4/5] minor test fixes --- scripts/test.sh | 4 ++-- tests/README.md | 6 ++++++ tests/cleanup.yml | 12 ++++++++++++ tests/dhcrelay_destination.yml | 5 ----- tests/dhcrelay_relay.yml | 8 -------- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index 12d177d..eca49e8 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -147,10 +147,10 @@ run_test 'openvpn_client_override' 0 # check mode => dependency on server-entry # run_test 'openvpn_client_export' 1 run_test 'nginx_general' 1 run_test 'nginx_upstream_server' 1 -run_test 'system' 1 -run_test 'package' 1 run_test 'dhcrelay_destination' 1 run_test 'dhcrelay_relay' 1 +run_test 'system' 1 +run_test 'package' 1 echo '' echo '##############################' diff --git a/tests/README.md b/tests/README.md index ec1786c..d88e5f5 100644 --- a/tests/README.md +++ b/tests/README.md @@ -55,6 +55,12 @@ The gateway tests will not work correctly if the LAN interface mismatches. You can provide your GW lan-if via env-vars: `TEST_FIREWALL_RULE_GRP_IF` +## DHCRelay + +The DHCRelay tests will not work correctly if the LAN interface mismatches. + +You can provide your lan-if via env-vars: `TEST_DHCRELAY_IF` + ---- ## Run diff --git a/tests/cleanup.yml b/tests/cleanup.yml index 1da24d5..d397af2 100644 --- a/tests/cleanup.yml +++ b/tests/cleanup.yml @@ -644,3 +644,15 @@ ansibleguy.opnsense.rule_interface_group: name: 'ANSIBLE_TEST' state: 'absent' + + - name: Cleanup dhcrelay + ansibleguy.opnsense.dhcrelay_relay: + interface: '{{ if_dhcrelay }}' + state: 'absent' + vars: + if_dhcrelay: "{{ lookup('ansible.builtin.env', 'TEST_DHCRELAY_IF') | default('lan', true) }}" + + - name: Cleanup dhcrelay-destination + ansibleguy.opnsense.dhcrelay_destination: + name: 'ANSIBLE_TEST_1_1' + state: 'absent' diff --git a/tests/dhcrelay_destination.yml b/tests/dhcrelay_destination.yml index c67a588..265493c 100644 --- a/tests/dhcrelay_destination.yml +++ b/tests/dhcrelay_destination.yml @@ -49,7 +49,6 @@ name: 'ANSIBLE_TEST_1_1' server: - '192.168.254.254' - reload: false # speed register: opn3 failed_when: > opn3.failed or @@ -61,7 +60,6 @@ server: - '192.168.254.252' - '192.168.254.253' - reload: false # speed register: opn4 failed_when: > opn4.failed or @@ -73,7 +71,6 @@ server: - '192.168.254.252' - '192.168.254.253' - reload: false # speed register: opn5 failed_when: > opn5.failed or @@ -84,7 +81,6 @@ ansibleguy.opnsense.dhcrelay_destination: name: 'ANSIBLE_TEST_1_2' state: 'absent' - reload: false # speed register: opn6 failed_when: > opn6.failed or @@ -103,7 +99,6 @@ ansibleguy.opnsense.dhcrelay_destination: name: 'ANSIBLE_TEST_1_1' state: 'absent' - reload: false # speed when: not ansible_check_mode - name: Listing diff --git a/tests/dhcrelay_relay.yml b/tests/dhcrelay_relay.yml index 719faf8..5a3f1e6 100644 --- a/tests/dhcrelay_relay.yml +++ b/tests/dhcrelay_relay.yml @@ -55,14 +55,12 @@ name: 'ANSIBLE_TEST_1_1' server: - '192.168.254.254' - reload: false # speed when: not ansible_check_mode - name: Adding 1 ansibleguy.opnsense.dhcrelay_relay: interface: '{{ if_dhcrelay }}' destination: 'ANSIBLE_TEST_1_1' - reload: false # speed register: opn3 failed_when: > opn3.failed or @@ -72,7 +70,6 @@ ansibleguy.opnsense.dhcrelay_relay: interface: '{{ if_dhcrelay }}' destination: 'ANSIBLE_TEST_1_1' - reload: false # speed register: opn4 failed_when: > opn4.failed or @@ -84,7 +81,6 @@ interface: '{{ if_dhcrelay }}' destination: 'ANSIBLE_TEST_1_1' enabled: true - reload: false # speed register: opn5 failed_when: > opn5.failed or @@ -96,7 +92,6 @@ interface: '{{ if_dhcrelay }}' destination: 'ANSIBLE_TEST_1_1' enabled: true - reload: false # speed register: opn6 failed_when: > opn6.failed or @@ -115,8 +110,6 @@ ansibleguy.opnsense.dhcrelay_relay: interface: '{{ if_dhcrelay }}' state: 'absent' - reload: false # speed - when: not ansible_check_mode register: opn6 failed_when: > opn6.failed or @@ -127,7 +120,6 @@ ansibleguy.opnsense.dhcrelay_destination: name: 'ANSIBLE_TEST_1_1' state: 'absent' - reload: false # speed when: not ansible_check_mode - name: Listing From 238b668fd6b42772f714b087982e98a4d613d590 Mon Sep 17 00:00:00 2001 From: Pascal Rath Date: Sun, 6 Oct 2024 14:29:47 +0200 Subject: [PATCH 5/5] add reload action --- docs/source/modules/2_reload.rst | 2 +- plugins/modules/reload.py | 5 +++++ tests/reload.yml | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/source/modules/2_reload.rst b/docs/source/modules/2_reload.rst index 938724a..b5c5d60 100644 --- a/docs/source/modules/2_reload.rst +++ b/docs/source/modules/2_reload.rst @@ -26,7 +26,7 @@ Definition :header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment" :widths: 15 10 10 10 10 45 - "target","string","true","\-","tgt, t","What part of the running config should be reloaded. One of: 'alias', 'rule', 'route', 'cron', 'unbound', 'syslog', 'ipsec', 'ipsec_legacy', 'shaper', 'monit', 'wireguard', 'interface_vlan', 'interface_vxlan', 'interface_vip', 'frr', 'webproxy', 'bind', 'ids'" + "target","string","true","\-","tgt, t","What part of the running config should be reloaded. One of: 'alias', 'rule', 'route', 'cron', 'unbound', 'syslog', 'ipsec', 'ipsec_legacy', 'shaper', 'monit', 'wireguard', 'interface_vlan', 'interface_vxlan', 'interface_vip', 'frr', 'webproxy', 'bind', 'ids', 'dhcrelay'" .. include:: ../_include/param_basic.rst diff --git a/plugins/modules/reload.py b/plugins/modules/reload.py index 9e863a9..8ac9c90 100644 --- a/plugins/modules/reload.py +++ b/plugins/modules/reload.py @@ -48,6 +48,7 @@ def run_module(): 'bind', 'ids', 'openvpn', + 'dhcrelay', ], description='What part of the running config should be reloaded' ), @@ -152,6 +153,10 @@ def run_module(): from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.openvpn_client import \ Client as Target_Obj + elif target == 'dhcrelay': + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.dhcrelay_relay import \ + DhcRelayRelay as Target_Obj + except MODULE_EXCEPTIONS: module_dependency_error() diff --git a/tests/reload.yml b/tests/reload.yml index 727d23e..0cac9fa 100644 --- a/tests/reload.yml +++ b/tests/reload.yml @@ -35,4 +35,5 @@ - 'bind' - 'ids' - 'openvpn' + - 'dhcrelay' # - 'gateway' # issue 88