Skip to content

Commit

Permalink
Merge pull request #30 from cisco-open/fr/cluster
Browse files Browse the repository at this point in the history
cluster configuration
  • Loading branch information
przsus authored Oct 9, 2024
2 parents 61b5bd4 + d68063b commit c0bb7c5
Show file tree
Hide file tree
Showing 13 changed files with 489 additions and 40 deletions.
1 change: 1 addition & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .dev_dir/example_dev_vars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion ansible.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace: cisco
name: catalystwan
version: 0.2.1
version: 0.2.2
readme: README.md
authors:
- Arkadiusz Cichon <[email protected]>
Expand Down
44 changes: 44 additions & 0 deletions playbooks/tests/test_module_cluster_management.yml
Original file line number Diff line number Diff line change
@@ -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.admin_username }}"
password: "{{ vmanage.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
108 changes: 71 additions & 37 deletions plugins/module_utils/vmanage_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


import logging
import time
import traceback
from typing import Any, Callable, Dict, Protocol, TypeVar

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand All @@ -157,7 +170,15 @@ 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,
fail_on_exception: bool = True,
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.
Expand All @@ -175,11 +196,24 @@ 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,
fail_on_exception,
num_retries - 1,
retry_interval_seconds,
**kwargs,
)
elif fail_on_exception:
self.fail_json(
msg=f"Could not perform '{action_name}' action.\nManager error: {ex.info}",
exception=traceback.format_exc(),
)

def execute_action_safely(
self,
Expand Down
Loading

0 comments on commit c0bb7c5

Please sign in to comment.