From a0e1adcfcb7d3cf49fbba7c39c11ad256494eb1c Mon Sep 17 00:00:00 2001 From: przsus <101723670+przsus@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:29:53 +0200 Subject: [PATCH 1/4] cluster configuration --- .ansible-lint | 1 + .dev_dir/example_dev_vars.yml | 1 + ansible.cfg | 2 +- .../tests/test_module_cluster_management.yml | 44 ++++ plugins/module_utils/vmanage_module.py | 100 +++++--- plugins/modules/cluster_management.py | 214 ++++++++++++++++++ roles/cluster/README.md | 58 +++++ roles/cluster/defaults/main.yml | 8 + roles/cluster/meta/main.yml | 15 ++ roles/cluster/tasks/main.yml | 38 ++++ roles/cluster/tasks/variables_assertion.yml | 20 ++ 11 files changed, 463 insertions(+), 38 deletions(-) create mode 100644 playbooks/tests/test_module_cluster_management.yml create mode 100644 plugins/modules/cluster_management.py create mode 100644 roles/cluster/README.md create mode 100644 roles/cluster/defaults/main.yml create mode 100644 roles/cluster/meta/main.yml create mode 100644 roles/cluster/tasks/main.yml create mode 100644 roles/cluster/tasks/variables_assertion.yml diff --git a/.ansible-lint b/.ansible-lint index a7cb38d..5a543a3 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -25,6 +25,7 @@ mock_modules: - cisco.catalystwan.administration_settings - cisco.catalystwan.alarms - cisco.catalystwan.cli_templates + - cisco.catalystwan.cluster_management - cisco.catalystwan.device_templates - cisco.catalystwan.devices_certificates - cisco.catalystwan.devices_controllers diff --git a/.dev_dir/example_dev_vars.yml b/.dev_dir/example_dev_vars.yml index 29cdc6a..8ac87e3 100644 --- a/.dev_dir/example_dev_vars.yml +++ b/.dev_dir/example_dev_vars.yml @@ -38,6 +38,7 @@ vmanage_instances: mgmt_public_ip: null system_ip: null transport_public_ip: null + cluster_private_ip: null vsmart_instances: - admin_password: null admin_username: null diff --git a/ansible.cfg b/ansible.cfg index 06c4ff0..52e85f2 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -3,7 +3,7 @@ roles_path = ./roles #vault_password_file = /path/to/vault/password/file stdout_callback = yaml bin_ansible_callbacks = True -callback_whitelist = profile_tasks +callbacks_enabled = profile_tasks remote_tmp = /tmp/.ansible_remote/tmp local_tmp = /tmp/.ansible_local/tmp log_path = ./ansible.log diff --git a/playbooks/tests/test_module_cluster_management.yml b/playbooks/tests/test_module_cluster_management.yml new file mode 100644 index 0000000..1eb3437 --- /dev/null +++ b/playbooks/tests/test_module_cluster_management.yml @@ -0,0 +1,44 @@ +# Copyright 2024 Cisco Systems, Inc. and its affiliates +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +--- +- name: Testing playbook to verify cisco.catalystwan.cluster + hosts: localhost + gather_facts: false + vars_files: + - configuration_file_dev_vars.yml + tasks: + - name: "Edit cluster IP address for vManage {{ (vmanage_instances | first).hostname }}" + cisco.catalystwan.cluster_management: + wait_until_configured_seconds: 300 + vmanage_id: "0" + device_ip: "{{ (vmanage_instances | first).cluster_private_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + persona: "{{ (vmanage_instances | first).persona }}" + services: + sd-avc: + server: false + manager_authentication: + url: "{{ (vmanage_instances | first).mgmt_public_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + + - name: Add remaining instances to cluster + cisco.catalystwan.cluster_management: + wait_until_configured_seconds: 1800 + device_ip: "{{ vmanage.cluster_private_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + gen_csr: false + persona: "{{ vmanage.persona }}" + services: + sd-avc: + server: false + manager_authentication: + url: "{{ (vmanage_instances | first).mgmt_public_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + loop: "{{ vmanage_instances[1:] }}" + loop_control: + loop_var: vmanage diff --git a/plugins/module_utils/vmanage_module.py b/plugins/module_utils/vmanage_module.py index b3e855e..4d2bf6d 100644 --- a/plugins/module_utils/vmanage_module.py +++ b/plugins/module_utils/vmanage_module.py @@ -3,6 +3,7 @@ import logging +import time import traceback from typing import Any, Callable, Dict, Protocol, TypeVar @@ -64,10 +65,11 @@ class AnsibleCatalystwanModule: ) ) - def __init__(self, argument_spec=None, supports_check_mode=False, **kwargs): + def __init__(self, argument_spec=None, supports_check_mode=False, session_reconnect_retries=0, **kwargs): self.argument_spec = argument_spec if self.argument_spec is None: self.argument_spec = dict() + self.session_reconnect_retries = session_reconnect_retries self.argument_spec.update(self.common_args) self.module = AnsibleModule(argument_spec=self.argument_spec, supports_check_mode=supports_check_mode, **kwargs) @@ -103,39 +105,50 @@ def strip_none_values(value): return strip_none_values(self.params) + @staticmethod + def get_exception_string(exception) -> str: + if hasattr(exception, "message"): + return exception.message + else: + return repr(exception) + @property def session(self) -> ManagerSession: if self._session is None: - try: - self._session = create_manager_session( - url=self.module.params["manager_credentials"]["url"], - username=self.module.params["manager_credentials"]["username"], - password=self.module.params["manager_credentials"]["password"], - port=self.module.params["manager_credentials"]["port"], - logger=self._vmanage_logger, - ) - # Avoid catchall exceptions, they are not very useful unless the underlying API - # gives very good error messages pertaining the attempted action. - except ( - NewConnectionError, - ConnectionError, - ManagerRequestException, - TimeoutError, - UnauthorizedAccessError, - ) as exception: - manager_url = self.module.params["manager_credentials"]["url"] - if hasattr(exception, "message"): - exception_string = exception.message - else: - exception_string = repr(exception) - - self.module.fail_json( - msg=f"Cannot establish session with Manager: {manager_url}, exception: {exception_string}", - exception=traceback.format_exc(), - ) - - except Exception as exception: - self.module.fail_json(msg=f"Unknown exception: {exception}", exception=traceback.format_exc()) + reconnect_times = self.session_reconnect_retries + manager_url = self.module.params["manager_credentials"]["url"] + while True: + try: + self._session = create_manager_session( + url=manager_url, + username=self.module.params["manager_credentials"]["username"], + password=self.module.params["manager_credentials"]["password"], + port=self.module.params["manager_credentials"]["port"], + logger=self._vmanage_logger, + ) + break + # Avoid catchall exceptions, they are not very useful unless the underlying API + # gives very good error messages pertaining the attempted action. + except ( + NewConnectionError, + ConnectionError, + ManagerRequestException, + TimeoutError, + UnauthorizedAccessError, + ) as exception: + if reconnect_times: + reconnect_times = reconnect_times - 1 + time.sleep(1) + continue + else: + self.module.fail_json( + msg=f"Cannot establish session with Manager: {manager_url}, " + f"exception: {self.get_exception_string(exception)}", + exception=traceback.format_exc(), + ) + + except Exception as exception: + self.module.fail_json(msg=f"Unknown exception: {exception}", exception=traceback.format_exc()) return self._session @@ -157,7 +170,14 @@ def get_response_safely(self, get_data_func: GetDataFunc[ReturnType], **kwargs: ) def send_request_safely( - self, result: ModuleResult, action_name: str, send_func: Callable, response_key: str = None, **kwargs: Any + self, + result: ModuleResult, + action_name: str, + send_func: Callable, + response_key: str = None, + num_retries: int = 0, + retry_interval_seconds: int = 1, + **kwargs: Any, ) -> None: """ Simplify process of sending requests to Manager safely. Handle all kind of requests. @@ -175,11 +195,17 @@ def send_request_safely( result.response[f"{response_key}"] = response result.changed = True - except ManagerHTTPError as ex: - self.fail_json( - msg=f"Could not perform '{action_name}' action.\nManager error: {ex.info}", - exception=traceback.format_exc(), - ) + except (ManagerHTTPError, ManagerRequestException) as ex: + if num_retries: + time.sleep(retry_interval_seconds) + self.send_request_safely( + result, action_name, send_func, response_key, num_retries - 1, retry_interval_seconds, **kwargs + ) + else: + self.fail_json( + msg=f"Could not perform '{action_name}' action.\nManager error: {ex.info}", + exception=traceback.format_exc(), + ) def execute_action_safely( self, diff --git a/plugins/modules/cluster_management.py b/plugins/modules/cluster_management.py new file mode 100644 index 0000000..62325d7 --- /dev/null +++ b/plugins/modules/cluster_management.py @@ -0,0 +1,214 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright 2024 Cisco Systems, Inc. and its affiliates +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + + +DOCUMENTATION = r""" +--- +module: cluster_management +short_description: Cluster configuration for vManage devices +version_added: "0.2.1" +description: This module can be used to add or edit existing controller devices to cluster configuration. +options: + wait_until_configured_seconds: + description: + - How much time (in seconds) to wait for the device to connect to cluster post configuration. + type: int + default: 0 + vmanage_id: + description: + - Optional ID of vManage to edit. Don't set when adding new vManage instances to cluster. + type: str + device_ip: + description: + - Added/edited device IP address. + type: str + username: + description: + - Username for the device being managed. + type: str + password: + description: + - Password for the device being managed. + type: str + no_log: True + gen_csr: + description: + - Whether to generate a CSR (Certificate Signing Request) for the device. + type: bool + persona: + description: + - Persona of the device. Choices are 'COMPUTE_AND_DATA', 'COMPUTE', or 'DATA'. + type: str + choices: ["COMPUTE_AND_DATA", "COMPUTE", "DATA"] + services: + description: + - A dict containing the services of cluster device, + such as Cisco Software-Defined Application Visibility and Control. + type: dict +author: + - Przemyslaw Susko (sprzemys@cisco.com) +extends_documentation_fragment: + - cisco.catalystwan.manager_authentication +""" + +RETURN = r""" +msg: + description: Message detailing the outcome of the operation. + returned: always + type: str + sample: "Successfully updated requested vManage configuration." +response: + description: Detailed response from the vManage API if applicable. + returned: when API call is made + type: dict + sample: {"edit_vmanage": "successMessage": "Edit Node operation performed. The operation may take some time and + may cause application-server to restart in between"} +changed: + description: Whether or not the state was changed. + returned: always + type: bool + sample: true +""" + +EXAMPLES = r""" +# Example of using the module to edit parameters of vManage added to cluster +- name: "Edit vManage" + cisco.catalystwan.cluster_management: + wait_until_configured_seconds: 300 + vmanage_id: "0" + device_ip: "1.1.1.1" + username: "username" + password: "password" # pragma: allowlist secret + persona: "COMPUTE_AND_DATA" + services: + sd-avc: + server: false + +# Example of using the module to add a new vManage to cluster +- name: "Add vManage to cluster" + cisco.catalystwan.cluster_management: + wait_until_configured_seconds: 300 + device_ip: "2.2.2.2" + username: "username" + password: "password" # pragma: allowlist secret + gen_csr: false + persona: "DATA" + services: + sd-avc: + server: false +""" + +import time +from typing import Optional + +from catalystwan.endpoints.cluster_management import VManageSetup +from catalystwan.exceptions import ManagerRequestException + +from ..module_utils.result import ModuleResult +from ..module_utils.vmanage_module import AnsibleCatalystwanModule + + +def wait_for_connected_device(module, device_ip, timeout) -> Optional[str]: + start = time.time() + while True: + try: + connected_device = module.session.endpoints.cluster_management.get_connected_devices(device_ip) + if connected_device: + return None + if (time.time() - start) > timeout: + return f"reached timeout of {timeout}s" + time.sleep(1) + except ManagerRequestException: + time.sleep(1) + continue + return "unknown exception occurred" + + +def run_module(): + module_args = dict( + wait_until_configured_seconds=dict(type="int", default=0), + vmanage_id=dict(type=str), + device_ip=dict(type=str, required=True), + username=dict(type=str, required=True), + password=dict(type=str, no_log=True, required=True), + gen_csr=dict(type=bool, aliases=["genCSR"]), + persona=dict(type=str, choices=["COMPUTE_AND_DATA", "COMPUTE", "DATA"], required=True), + services=dict( + type="dict", + options=dict( + sd_avc=dict( + type="dict", + aliases=["sd-avc"], + options=dict( + server=dict(type="bool"), + ), + ), + ), + ), + ) + + module = AnsibleCatalystwanModule(argument_spec=module_args, session_reconnect_retries=180) + result = ModuleResult() + + vmanage_id = module.params.get("vmanage_id") + device_ip = module.params.get("device_ip") + + connected_device = module.session.endpoints.cluster_management.get_connected_devices(device_ip) + if connected_device: + result.changed = False + result.msg = f"Device {device_ip} already configured" + module.exit_json(**result.model_dump(mode="json")) + return + + payload = VManageSetup( + vmanage_id=vmanage_id, + device_ip=device_ip, + username=module.params.get("username"), + password=module.params.get("password"), + persona=module.params.get("persona"), + services=module.params.get("services"), + ) + + if vmanage_id: + module.send_request_safely( + result, + action_name="Cluster Management: Edit vManage", + send_func=module.session.endpoints.cluster_management.edit_vmanage, + payload=payload, + response_key="edit_vmanage", + ) + else: + module.session.request_timeout = 60 + module.send_request_safely( + result, + action_name="Cluster Management: Add vManage", + send_func=module.session.endpoints.cluster_management.add_vmanage, + payload=payload, + response_key="add_vmanage", + num_retries=30, + retry_interval_seconds=10, + ) + + if result.changed: + wait_until_configured_seconds = module.params.get("wait_until_configured_seconds") + if wait_until_configured_seconds: + error_msg = wait_for_connected_device(module, device_ip, wait_until_configured_seconds) + if error_msg: + module.fail_json(msg=f"Error during vManage configuration: {error_msg}") + return + result.msg = "Successfully updated requested vManage configuration." + else: + result.msg = "No changes to vManage configuration applied." + + module.exit_json(**result.model_dump(mode="json")) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/roles/cluster/README.md b/roles/cluster/README.md new file mode 100644 index 0000000..20b0b47 --- /dev/null +++ b/roles/cluster/README.md @@ -0,0 +1,58 @@ +Role Name +========= + +This Ansible role facilitates the process adding and editing controllers to cluster for Cisco SD-WAN vManage devices. + +Requirements +------------ + +- `cisco.catalystwan` collection installed. +- Access details for the Cisco Manager instance must be provided. + +Role Variables +-------------- +- `vmanage_instances`: A list of vManage instances containing management IP, admin username, and admin password. May also include vManage persona and services configuration for cluster usage. +- `default_services`: A list of services for cluster usage, such as `sd-avc`. + +Dependencies +------------ + +There are no external role dependencies. Only `cisco.catalystwan` collection is required. + +Example Playbook +---------------- + +```yaml +- name: Edit vManage cluster IP address + hosts: localhost + import_role: + name: cluster + vars: + vmanage_instances: + - admin_password: password + admin_username: user + cluster_private_ip: 10.0.3.4 + hostname: vManage1 + mgmt_public_ip: 170.170.170.10 + persona: COMPUTE_AND_DATA + cluster_services: + sd-avc: + server: true + - admin_password: password + admin_username: user + cluster_private_ip: 10.0.3.5 + hostname: vManage2 + mgmt_public_ip: 170.170.170.20 + persona: COMPUTE_AND_DATA + default_services: + sd-avc: + server: false +``` + +## License + +"GPL-3.0-only" + +## Author Information + +This role was created by Przemyslaw Susko diff --git a/roles/cluster/defaults/main.yml b/roles/cluster/defaults/main.yml new file mode 100644 index 0000000..b1ed903 --- /dev/null +++ b/roles/cluster/defaults/main.yml @@ -0,0 +1,8 @@ +# Copyright 2024 Cisco Systems, Inc. and its affiliates +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +--- + +default_services: + sd-avc: + server: false diff --git a/roles/cluster/meta/main.yml b/roles/cluster/meta/main.yml new file mode 100644 index 0000000..11798da --- /dev/null +++ b/roles/cluster/meta/main.yml @@ -0,0 +1,15 @@ +--- + +galaxy_info: + author: Przemyslaw Susko + description: Generate Manager CSR, add controlers and wait for their certificates and reachability + license: GPL-3.0-or-later + min_ansible_version: "2.16.6" + + galaxy_tags: + - cisco + - sdwan + - catalystwan + - networking + +dependencies: [] diff --git a/roles/cluster/tasks/main.yml b/roles/cluster/tasks/main.yml new file mode 100644 index 0000000..2b50a54 --- /dev/null +++ b/roles/cluster/tasks/main.yml @@ -0,0 +1,38 @@ +# Copyright 2024 Cisco Systems, Inc. and its affiliates +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +--- + +- name: Verify required variables for selected role + ansible.builtin.include_tasks: variables_assertion.yml + +- name: "Edit cluster IP address for vManage {{ (vmanage_instances | first).hostname }}" + cisco.catalystwan.cluster_management: + wait_until_configured_seconds: 300 + vmanage_id: "0" + device_ip: "{{ (vmanage_instances | first).cluster_private_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + persona: "{{ (vmanage_instances | first).persona }}" + services: "{{ (vmanage_instances | first).cluster_services | default(default_services) }}" + manager_authentication: + url: "{{ (vmanage_instances | first).mgmt_public_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + +- name: Add remaining instances to cluster + cisco.catalystwan.cluster_management: + wait_until_configured_seconds: 1800 + device_ip: "{{ vmanage.cluster_private_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + gen_csr: false + persona: "{{ vmanage.persona }}" + services: "{{ vmanage.cluster_services | default(default_services) }}" + manager_authentication: + url: "{{ (vmanage_instances | first).mgmt_public_ip }}" + username: "{{ (vmanage_instances | first).admin_username }}" + password: "{{ (vmanage_instances | first).admin_password }}" + loop: "{{ vmanage_instances[1:] }}" + loop_control: + loop_var: vmanage diff --git a/roles/cluster/tasks/variables_assertion.yml b/roles/cluster/tasks/variables_assertion.yml new file mode 100644 index 0000000..16c62f9 --- /dev/null +++ b/roles/cluster/tasks/variables_assertion.yml @@ -0,0 +1,20 @@ +# Copyright 2024 Cisco Systems, Inc. and its affiliates +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +--- + +- name: Assert that required variables are provided + ansible.builtin.assert: + that: + - required_var + - required_var is defined + - required_var != None + - required_var != "None" + - required_var != "" + - required_var | length > 0 + fail_msg: "Your SD-WAN initial config file missing required variable: {{ required_var }}" + quiet: true + loop: + - "{{ vmanage_instances }}" + loop_control: + loop_var: required_var From 588394acfcc6a2862d61b60efc39b41182303525 Mon Sep 17 00:00:00 2001 From: przsus <101723670+przsus@users.noreply.github.com> Date: Tue, 8 Oct 2024 13:12:29 +0200 Subject: [PATCH 2/4] Update roles/cluster/README.md Co-authored-by: cicharka <93913624+cicharka@users.noreply.github.com> --- roles/cluster/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/cluster/README.md b/roles/cluster/README.md index 20b0b47..061ac7d 100644 --- a/roles/cluster/README.md +++ b/roles/cluster/README.md @@ -1,7 +1,7 @@ Role Name ========= -This Ansible role facilitates the process adding and editing controllers to cluster for Cisco SD-WAN vManage devices. +This Ansible role facilitates the process of adding and editing controllers to the cluster for Cisco SD-WAN vManage devices. Requirements ------------ From 360100940c069df286ad40b19bd6d2df38d4faa4 Mon Sep 17 00:00:00 2001 From: przsus <101723670+przsus@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:46:12 +0200 Subject: [PATCH 3/4] code review remarks --- .../tests/test_module_cluster_management.yml | 4 +-- plugins/module_utils/vmanage_module.py | 12 ++++++-- plugins/modules/cluster_management.py | 30 ++++++++++++++----- pyproject.toml | 2 +- roles/cluster/tasks/main.yml | 5 ++-- roles/cluster/tasks/variables_assertion.yml | 1 + 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/playbooks/tests/test_module_cluster_management.yml b/playbooks/tests/test_module_cluster_management.yml index 1eb3437..9d9f876 100644 --- a/playbooks/tests/test_module_cluster_management.yml +++ b/playbooks/tests/test_module_cluster_management.yml @@ -28,8 +28,8 @@ cisco.catalystwan.cluster_management: wait_until_configured_seconds: 1800 device_ip: "{{ vmanage.cluster_private_ip }}" - username: "{{ (vmanage_instances | first).admin_username }}" - password: "{{ (vmanage_instances | first).admin_password }}" + username: "{{ vmanage.admin_username }}" + password: "{{ vmanage.admin_password }}" gen_csr: false persona: "{{ vmanage.persona }}" services: diff --git a/plugins/module_utils/vmanage_module.py b/plugins/module_utils/vmanage_module.py index 4d2bf6d..03eaeb8 100644 --- a/plugins/module_utils/vmanage_module.py +++ b/plugins/module_utils/vmanage_module.py @@ -175,6 +175,7 @@ def send_request_safely( action_name: str, send_func: Callable, response_key: str = None, + fail_on_exception: bool = True, num_retries: int = 0, retry_interval_seconds: int = 1, **kwargs: Any, @@ -199,9 +200,16 @@ def send_request_safely( if num_retries: time.sleep(retry_interval_seconds) self.send_request_safely( - result, action_name, send_func, response_key, num_retries - 1, retry_interval_seconds, **kwargs + result, + action_name, + send_func, + response_key, + fail_on_exception, + num_retries - 1, + retry_interval_seconds, + **kwargs, ) - else: + elif fail_on_exception: self.fail_json( msg=f"Could not perform '{action_name}' action.\nManager error: {ex.info}", exception=traceback.format_exc(), diff --git a/plugins/modules/cluster_management.py b/plugins/modules/cluster_management.py index 62325d7..fdde065 100644 --- a/plugins/modules/cluster_management.py +++ b/plugins/modules/cluster_management.py @@ -111,12 +111,28 @@ from ..module_utils.vmanage_module import AnsibleCatalystwanModule -def wait_for_connected_device(module, device_ip, timeout) -> Optional[str]: +def get_connected_devices(module, device_ip): + result = ModuleResult() + module.send_request_safely( + result, + action_name=f"Get connected devices for {device_ip}", + send_func=module.session.endpoints.cluster_management.get_connected_devices, + vmanageIP=device_ip, + response_key="connected_devices", + fail_on_exception=False, + ) + try: + return result.response["connected_devices"] + except KeyError: + return None + + +def wait_for_connected_devices(module, device_ip, timeout) -> Optional[str]: start = time.time() while True: try: - connected_device = module.session.endpoints.cluster_management.get_connected_devices(device_ip) - if connected_device: + connected_devices = get_connected_devices(module, device_ip) + if connected_devices: return None if (time.time() - start) > timeout: return f"reached timeout of {timeout}s" @@ -156,12 +172,11 @@ def run_module(): vmanage_id = module.params.get("vmanage_id") device_ip = module.params.get("device_ip") - connected_device = module.session.endpoints.cluster_management.get_connected_devices(device_ip) - if connected_device: + connected_devices = get_connected_devices(module, device_ip) + if connected_devices: result.changed = False result.msg = f"Device {device_ip} already configured" module.exit_json(**result.model_dump(mode="json")) - return payload = VManageSetup( vmanage_id=vmanage_id, @@ -195,10 +210,9 @@ def run_module(): if result.changed: wait_until_configured_seconds = module.params.get("wait_until_configured_seconds") if wait_until_configured_seconds: - error_msg = wait_for_connected_device(module, device_ip, wait_until_configured_seconds) + error_msg = wait_for_connected_devices(module, device_ip, wait_until_configured_seconds) if error_msg: module.fail_json(msg=f"Error during vManage configuration: {error_msg}") - return result.msg = "Successfully updated requested vManage configuration." else: result.msg = "No changes to vManage configuration applied." diff --git a/pyproject.toml b/pyproject.toml index 0661416..e2f4ed0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ readme = "README.md" python = "^3.10" ansible-core = "2.16.6" ansible = "9.4.0" -catalystwan = "v0.34.0dev5" +catalystwan = "v0.35.5dev0" flake8 = "5.0.4" black = "24.3.0" pre-commit = "3.7" diff --git a/roles/cluster/tasks/main.yml b/roles/cluster/tasks/main.yml index 2b50a54..1aa34fd 100644 --- a/roles/cluster/tasks/main.yml +++ b/roles/cluster/tasks/main.yml @@ -24,8 +24,8 @@ cisco.catalystwan.cluster_management: wait_until_configured_seconds: 1800 device_ip: "{{ vmanage.cluster_private_ip }}" - username: "{{ (vmanage_instances | first).admin_username }}" - password: "{{ (vmanage_instances | first).admin_password }}" + username: "{{ vmanage.admin_username }}" + password: "{{ vmanage.admin_password }}" gen_csr: false persona: "{{ vmanage.persona }}" services: "{{ vmanage.cluster_services | default(default_services) }}" @@ -36,3 +36,4 @@ loop: "{{ vmanage_instances[1:] }}" loop_control: loop_var: vmanage + when: vmanage.cluster_private_ip is defined diff --git a/roles/cluster/tasks/variables_assertion.yml b/roles/cluster/tasks/variables_assertion.yml index 16c62f9..b6edcb6 100644 --- a/roles/cluster/tasks/variables_assertion.yml +++ b/roles/cluster/tasks/variables_assertion.yml @@ -16,5 +16,6 @@ quiet: true loop: - "{{ vmanage_instances }}" + - "{{ (vmanage_instances | first).cluster_private_ip }}" loop_control: loop_var: required_var From d68063bcd3eeadcdca3d7078c8db461b2f014b76 Mon Sep 17 00:00:00 2001 From: przsus <101723670+przsus@users.noreply.github.com> Date: Wed, 9 Oct 2024 12:48:53 +0200 Subject: [PATCH 4/4] bump galaxy version --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 286d49e..a74d8e4 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,6 +1,6 @@ namespace: cisco name: catalystwan -version: 0.2.1 +version: 0.2.2 readme: README.md authors: - Arkadiusz Cichon