diff options
| author | omnom62 <omnom62@outlook.com> | 2026-05-31 07:25:03 +1000 |
|---|---|---|
| committer | omnom62 <omnom62@outlook.com> | 2026-05-31 07:25:03 +1000 |
| commit | 6a161ed8f263e152ebfd227e669a51773de5a028 (patch) | |
| tree | efd9cef101e459daa021b98ba00e5f75d897048e /plugins | |
| parent | f37d4e313154ea7ea40250849549065196fab722 (diff) | |
| download | rest.vyos-6a161ed8f263e152ebfd227e669a51773de5a028.tar.gz rest.vyos-6a161ed8f263e152ebfd227e669a51773de5a028.zip | |
updated tests
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/httpapi/vyos.py | 8 | ||||
| -rw-r--r-- | plugins/module_utils/vyos.py | 113 | ||||
| -rw-r--r-- | plugins/module_utils/vyos_rest.py | 48 | ||||
| -rw-r--r-- | plugins/modules/vyos_ntp_global.py | 13 |
4 files changed, 93 insertions, 89 deletions
diff --git a/plugins/httpapi/vyos.py b/plugins/httpapi/vyos.py index 1719254..6dd6042 100644 --- a/plugins/httpapi/vyos.py +++ b/plugins/httpapi/vyos.py @@ -105,11 +105,15 @@ class HttpApi(HttpApiBase): Raises: ConnectionError: on HTTP error or VyOS success=false response. """ + try: api_key = self._get_api_key() - body = json.dumps(payload) - form_data = urlencode({"data": body, "key": api_key}) + if "_raw_list" in payload: + body = json.dumps(payload["_raw_list"]) + else: + body = json.dumps(payload) + form_data = urlencode({"data": body, "key": api_key}) response, response_data = self.connection.send( endpoint, data=form_data, diff --git a/plugins/module_utils/vyos.py b/plugins/module_utils/vyos.py index 87fc37b..82670e7 100644 --- a/plugins/module_utils/vyos.py +++ b/plugins/module_utils/vyos.py @@ -62,58 +62,75 @@ class VyOSModule: # Write # ------------------------------------------------------------------ - def apply_commands(self, commands): - """Execute a list of ``(op, path)`` command tuples against the device. - - Args: - commands (list): Each item is a 2-tuple ``(op, path)`` where: - - *op* is ``"set"`` or ``"delete"`` - - *path* is a list of config path tokens - - Optionally a 3-tuple ``(op, path, value)`` for leaf nodes - that carry a value. - - Returns: - list: Results from each command (dicts with ``op`` and ``path``). - - Raises: - VyOSRestError: If a command fails and cannot be recovered. - - Notes: - **Version-adaptive set:** if a ``set`` is rejected by the device, - the method retries once with the last path segment removed. - This handles schema simplifications between VyOS releases - (e.g. ``allow-client address <prefix>`` -> ``allow-client <prefix>`` - in VyOS 1.5+). - - **Idempotent delete:** ``delete`` failures are silently ignored - (the path is already absent). - """ - results = [] + # def apply_commands(self, commands): + # """Execute a list of ``(op, path)`` command tuples against the device. + + # Args: + # commands (list): Each item is a 2-tuple ``(op, path)`` where: + # - *op* is ``"set"`` or ``"delete"`` + # - *path* is a list of config path tokens + + # Optionally a 3-tuple ``(op, path, value)`` for leaf nodes + # that carry a value. + + # Returns: + # list: Results from each command (dicts with ``op`` and ``path``). + + # Raises: + # VyOSRestError: If a command fails and cannot be recovered. + + # Notes: + # **Version-adaptive set:** if a ``set`` is rejected by the device, + # the method retries once with the last path segment removed. + # This handles schema simplifications between VyOS releases + # (e.g. ``allow-client address <prefix>`` -> ``allow-client <prefix>`` + # in VyOS 1.5+). + + # **Idempotent delete:** ``delete`` failures are silently ignored + # (the path is already absent). + # """ + # results = [] + + # for cmd in commands: + # # Support two command formats: + # # Tuple: ("set", ["path", "tokens"]) or ("set", ["path"], "value") + # # Dict: {"op": "set", "path": ["path", "tokens"]} + # if isinstance(cmd, dict): + # op = cmd["op"] + # path = list(cmd["path"]) + # value = cmd.get("value") + # else: + # op = cmd[0] + # path = list(cmd[1]) + # value = cmd[2] if len(cmd) > 2 else None + + # if op == "set": + # results.append(self._apply_set(path, value)) + # elif op == "delete": + # results.append(self._apply_delete(path)) + # else: + # self._module.fail_json( + # msg="Unknown command op '{op}' in apply_commands".format(op=op), + # ) + + # return results + def apply_commands(self, commands): + if not commands: + return [] + payload = [] for cmd in commands: - # Support two command formats: - # Tuple: ("set", ["path", "tokens"]) or ("set", ["path"], "value") - # Dict: {"op": "set", "path": ["path", "tokens"]} if isinstance(cmd, dict): - op = cmd["op"] - path = list(cmd["path"]) - value = cmd.get("value") - else: - op = cmd[0] - path = list(cmd[1]) - value = cmd[2] if len(cmd) > 2 else None - - if op == "set": - results.append(self._apply_set(path, value)) - elif op == "delete": - results.append(self._apply_delete(path)) + op, path = cmd["op"], list(cmd["path"]) else: - self._module.fail_json( - msg="Unknown command op '{op}' in apply_commands".format(op=op), - ) - - return results + op, path = cmd[0], list(cmd[1]) + payload.append({"op": op, "path": path}) + try: + return self._client.configure_batch(payload) + except VyOSRestError as exc: + self._module.fail_json( + msg="apply_commands failed: {e}".format(e=str(exc)), + ) def _apply_set(self, path, value=None): """Set a config path, retrying with a shortened path on failure.""" diff --git a/plugins/module_utils/vyos_rest.py b/plugins/module_utils/vyos_rest.py index 95b3aac..aaf2b23 100644 --- a/plugins/module_utils/vyos_rest.py +++ b/plugins/module_utils/vyos_rest.py @@ -1,36 +1,5 @@ """ VyOS REST API client utility — supports both connection modes. - -**httpapi mode (recommended)**:: - - # inventory - vyos15x ansible_host=192.168.122.194 - ansible_network_os=vyos.rest.vyos - ansible_connection=ansible.netcommon.httpapi - ansible_httpapi_use_ssl=true - ansible_httpapi_port=443 - ansible_httpapi_validate_certs=false - ansible_httpapi_api_key=vyos123 - - # playbook — no connection params needed on any task - - vyos.rest.vyos_banner: - banner: pre-login - text: "Authorised use only." - state: present - -**local mode (alternative, no inventory network_os required)**:: - - - vyos.rest.vyos_banner: - hostname: 192.168.122.194 - api_key: vyos123 - verify_ssl: false - banner: pre-login - text: "Authorised use only." - state: present - -Both modes call the same VyOS endpoints. The httpapi mode routes calls -through the persistent connection daemon (better for large inventories); -the local mode opens a new HTTPS connection per task. """ from __future__ import absolute_import, division, print_function @@ -45,7 +14,7 @@ import os try: from urllib.parse import urlencode except ImportError: - from urllib import urlencode # Python 2 + from urllib import urlencode try: import urllib3 @@ -218,6 +187,21 @@ class VyOSRestClient: def image_delete(self, name): return self._post("/image", {"op": "delete", "name": name}) + def configure_batch(self, commands): + """Send all commands as a single atomic commit.""" + if self._mode == "httpapi": + try: + return self._conn.send_request( + endpoint="/configure", + _raw_list=commands, + ) + except ConnectionError as exc: + raise VyOSRestError(str(exc)) + except Exception as exc: + raise VyOSRestError( + "configure_batch failed: {e}".format(e=str(exc)), + ) + def config_file_save(self, path=None): payload = {"op": "save"} if path: diff --git a/plugins/modules/vyos_ntp_global.py b/plugins/modules/vyos_ntp_global.py index 185dc02..88073e1 100644 --- a/plugins/modules/vyos_ntp_global.py +++ b/plugins/modules/vyos_ntp_global.py @@ -218,13 +218,12 @@ def build_commands(desired, existing, state): cmds = [] if state == "overridden": - if existing["allow_clients"]: - cmds.append(("delete", ["service", "ntp", "allow-client"])) - if existing["listen_addresses"]: - cmds.append(("delete", ["service", "ntp", "listen-address"])) - if existing["servers"]: - cmds.append(("delete", ["service", "ntp", "server"])) - state = "merged" + state = "replaced" + + if state == "deleted": + if existing["servers"] or existing["allow_clients"] or existing["listen_addresses"]: + cmds.append(("delete", ["service", "ntp"])) + return cmds cmds += diff_list( "allow-client", |
