Skip to content

Commit

Permalink
Fix(cv_facts_v3): raise errors when svcaccount/user is not authorized (
Browse files Browse the repository at this point in the history
…#677)

* Fix(cv_facts_v3): return authorization error when svc token expires

* reverting previous changes and raising errors instead

* changing exception to CvpClientError

* fixing ansible lint issues

* fixing ansible lint issues

* adding CvpRequestError 403 handling for device tools

* adding CvpRequestError 403 handling for tag tools

* pylint fix

* adding CvpRequestError 403 handling for apply image

* adding CvpRequestError 403 handling for CC, task, container

* update error messages for device tools

* pep8 fix

* pylint fix-again

---------

Co-authored-by: Sugetha Chandhrasekar <sugethakch@arista.com>
  • Loading branch information
noredistribution and sugetha24 committed Nov 20, 2023
1 parent 2258ca5 commit 290363f
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,12 @@ def module_action(self, change: dict, name: str = None, state: str = "show", cha
MODULE_LOGGER.debug("Successfully deleted: %s", change_id)
changed = True
except Exception as e:
self.__ansible.fail_json(msg="{0}".format(e))
if "Forbidden" in str(e):
message = "Failed to delete Change Control. User is unauthorized!"
else:
message = str(e)
logging.error(message)
self.__ansible.fail_json(msg="{0}".format(message))

return changed, {'remove': []}, warnings

Expand Down Expand Up @@ -704,7 +709,12 @@ def module_action(self, change: dict, name: str = None, state: str = "show", cha
data = cc_structure['key']

except Exception as e:
self.__ansible.fail_json(msg="{0}".format(e))
if "Forbidden" in str(e):
message = "Failed to create Change Control. User is unauthorized!"
else:
message = str(e)
logging.error(message)
self.__ansible.fail_json(msg="{0}".format(message))

elif state in ['approve', 'unapprove', 'execute', 'schedule', 'approve_and_execute', 'schedule_and_approve'] and self.__check_mode is False:
MODULE_LOGGER.debug("Change control state: %s", state)
Expand Down Expand Up @@ -764,9 +774,14 @@ def module_action(self, change: dict, name: str = None, state: str = "show", cha
e = "Change control {0} id not found".format(cc_id)
self.__ansible.fail_json(msg="{0}".format(e))
return changed, {"approve": change_id}, warnings
except CvpRequestError:
except CvpRequestError as e:
# Skip this - covers the case where an approved CC is approved again
pass
if "Forbidden" in str(e):
message = "Failed to approve Change Control. User is unauthorized!"
self.__ansible.fail_json(msg="{0}".format(message))
logging.error(str(message))
else:
pass
except Exception as e:
self.__ansible.fail_json(msg="{0}".format(e))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from ansible_collections.arista.cvp.plugins.module_utils.tools_schema import validate_json_schema
from ansible_collections.arista.cvp.plugins.module_utils.resources.exceptions import AnsibleCVPApiError, AnsibleCVPNotFoundError, CVPRessource
try:
from cvprac.cvp_client_errors import CvpClientError, CvpApiError
from cvprac.cvp_client_errors import CvpClientError, CvpApiError, CvpRequestError
HAS_CVPRAC = True
except ImportError:
HAS_CVPRAC = False
Expand Down Expand Up @@ -356,6 +356,13 @@ def __configlet_add(self, container: dict, configlets: list, save_topology: bool
container=container,
create_task=save_topology
)
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error configuring configlets. User is unauthorized!"
else:
message = "Error configuring configlets " + str(configlets) + " to container " + str(container) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
except CvpApiError as e:
message = "Error configuring configlets " + str(configlets) + " to container " + str(container) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
Expand Down Expand Up @@ -425,6 +432,13 @@ def __configlet_del(self, container: dict, configlets: list, save_topology: bool
container=container,
create_task=save_topology
)
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error removing configlets. User is unauthorized!"
else:
message = "Error removing configlets " + str(configlets) + " to container " + str(container) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
except CvpApiError as e:
message = "Error removing configlets " + str(configlets) + " from container " + str(container) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
Expand Down Expand Up @@ -507,6 +521,13 @@ def __image_bundle_add(self, container: dict, image_bundle: str):
container[Api.generic.NAME],
'container'
)
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error applying bundle to container. User is unauthorized!"
else:
message = "Error applying bundle to container " + str(container[Api.generic.NAME]) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
except CvpApiError as catch_error:
MODULE_LOGGER.error('Error applying bundle to device: %s', str(catch_error))
self.__ansible.fail_json(msg='Error applying bundle to container' + container[Api.generic.NAME] + ': ' + catch_error)
Expand Down Expand Up @@ -567,6 +588,13 @@ def __image_bundle_del(self, container: dict):
container[Api.generic.NAME],
'container'
)
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error removing bundle from container. User is unauthorized!"
else:
message = "Error removing bundle from container " + str(container[Api.generic.NAME]) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
except CvpApiError as catch_error:
MODULE_LOGGER.error('Error removing bundle from container: %s', str(catch_error))
self.__ansible.fail_json(msg='Error removing bundle from container: ' + container[Api.generic.NAME] + ': ' + catch_error)
Expand Down Expand Up @@ -839,6 +867,13 @@ def create_container(self, container: str, parent: str):
try:
resp = self.__cvp_client.api.add_container(
container_name=container, parent_key=parent_id, parent_name=parent)
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error creating container. User is unauthorized!"
else:
message = "Error creating container " + str(container) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
except CvpApiError as e:
# Add Ansible error management
message = "Error creating container " + str(container) + " on CV. Exception: " + str(e)
Expand Down Expand Up @@ -915,6 +950,13 @@ def delete_container(self, container: str, parent: str):
try:
resp = self.__cvp_client.api.delete_container(
container_name=container, container_key=container_id, parent_key=parent_id, parent_name=parent)
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error deleting container. User is unauthorized!"
else:
message = "Error deleting container " + str(container) + ". Exception: " + str(e)
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
except CvpApiError as e:
# Add Ansible error management
message = "Error deleting container " + str(container) + " on CV. Exception: " + str(e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,10 @@ def move_device(self, user_inventory: DeviceInventory):
error_message = f"Error to move device {device.fqdn} to container {device.container}"
MODULE_LOGGER.error(error_message)
self.__ansible.fail_json(msg=error_message)
except CvpRequestError:
error_message = f"Move device {device.fqdn} to container {device.container} failed. User is unauthorized!"
MODULE_LOGGER.error(error_message)
self.__ansible.fail_json(msg=error_message)
else:
if resp and resp['data']['status'] == 'success':
result_data.changed = True
Expand Down Expand Up @@ -1696,6 +1700,13 @@ def apply_bundle(self, user_inventory: DeviceInventory):
self.__ansible.fail_json(
msg=f"Error applying bundle to device {device.fqdn}: {str(catch_error)}"
)
except CvpRequestError as catch_error:
MODULE_LOGGER.error(
"Error applying bundle to device: %s", str(catch_error)
)
self.__ansible.fail_json(
msg=f"Error applying bundle to device {device.fqdn}: {str(catch_error)}"
)
else:
if resp and resp["data"]["status"] == "success":
result_data.changed = True
Expand Down Expand Up @@ -1924,6 +1935,10 @@ def apply_configlets(self, user_inventory: DeviceInventory):
self.__ansible.fail_json(
msg="Error applying configlets to device"
)
except CvpRequestError:
message = "Failed to apply configlets to device. User is unauthorized!"
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
else:
if resp["data"]["status"] == "success":
result_data.changed = True
Expand Down Expand Up @@ -2014,6 +2029,11 @@ def detach_configlets(self, user_inventory: DeviceInventory):
self.__ansible.fail_json(
msg=f"Error detaching configlets from device {device.fqdn}: {catch_error}"
)
except CvpRequestError:
MODULE_LOGGER.error("Error detaching configlets to device. User is unauthorized!")
self.__ansible.fail_json(
msg="Error detaching configlets to device. User is unauthorized!"
)
else:
if resp["data"]["status"] == "success":
result_data.changed = True
Expand Down Expand Up @@ -2213,6 +2233,10 @@ def delete_device(self, user_inventory: DeviceInventory):
self.__ansible.fail_json(
msg="Error removing device from provisioning"
)
except CvpRequestError:
message = "Failed to remove device from provisioning. User is unauthorized!"
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
else:
if resp["result"] == "success":
result_data.changed = True
Expand Down Expand Up @@ -2251,8 +2275,11 @@ def decommission_device(self, user_inventory: DeviceInventory):
except CvpApiError:
MODULE_LOGGER.error("Error decommissioning device")
self.__ansible.fail_json(msg="Error decommissioning device")
except CvpRequestError:
request_err_msg = f"Device with {device_id} does not exist or is not registered to decommission"
except CvpRequestError as e:
if "403 Forbidden" in e.msg:
request_err_msg = f"Failed to decommission device {device_id}. User is unauthorized!"
else:
request_err_msg = f"Device with {device_id} does not exist or is not registered to decommission"
MODULE_LOGGER.error(request_err_msg)
self.__ansible.fail_json(msg=request_err_msg)
else:
Expand Down Expand Up @@ -2315,6 +2342,10 @@ def reset_device(self, user_inventory: DeviceInventory):
except CvpApiError:
MODULE_LOGGER.error("Error resetting device")
self.__ansible.fail_json(msg="Error resetting device")
except CvpRequestError:
message = "Failed to reset device. Users is unauthorized!"
MODULE_LOGGER.error(message)
self.__ansible.fail_json(msg=message)
else:
if resp and resp["data"]["status"] == "success":
result_data.changed = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ def __fact_devices(self, filter: str = '.*', verbose: str = 'short'):
cv_devices = self.__cv_client.api.get_inventory()
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting devices facts: %s', str(error_msg))
raise error_msg
MODULE_LOGGER.info('Extract device data using filter %s', str(filter))
facts_builder = CvFactResource()
for device in cv_devices:
Expand All @@ -614,6 +615,7 @@ def __fact_containers(self, filter: str = '.*'):
cv_containers = self.__cv_client.api.get_containers()
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting containers facts: %s', str(error_msg))
raise error_msg
facts_builder = CvFactResource()
for container in cv_containers['data']:
if container[Api.generic.NAME] != 'Tenant':
Expand All @@ -637,7 +639,11 @@ def __fact_configlets(self, filter: str = '.*', configlets_per_call: int = 10):
configlets_per_call : int, optional
Number of configlets to retrieve per API call, by default 10
"""
max_range_calc = self.__cv_client.api.get_configlets(start=0, end=1)['total'] + 1
try:
max_range_calc = self.__cv_client.api.get_configlets(start=0, end=1)['total'] + 1
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting configlets facts: %s', str(error_msg))
raise error_msg
futures_list = []
results = []
with ThreadPoolExecutor(max_workers=self._max_worker) as executor:
Expand Down Expand Up @@ -678,6 +684,7 @@ def __fact_images(self, filter: str = '.*'):
cv_images = self.__cv_client.api.get_images()
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting images facts: %s', str(error_msg))
raise error_msg

facts_builder = CvFactResource()
for image in cv_images['data']:
Expand Down Expand Up @@ -710,18 +717,21 @@ def __fact_tasks(self, filter: str = '.*', verbose: str = 'short'):
cv_tasks = cv_tasks['data']
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting task facts: %s', str(error_msg))
raise error_msg
elif isinstance(filter, str):
# filter by task status
try:
cv_tasks = self.__cv_client.api.get_tasks_by_status(filter)
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting %s task facts: %s', filter, str(error_msg))
raise error_msg
elif isinstance(filter, int):
# filter by task_id
try:
cv_tasks = self.__cv_client.api.get_task_by_id(filter)
except CvpApiError as error_msg:
MODULE_LOGGER.error('Error when collecting %s task facts: %s', filter, str(error_msg))
raise error_msg

for task in cv_tasks:
MODULE_LOGGER.debug('Got following information for task: %s', str(task))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ def tasker(self, tags: list, mode: string, auto_create: bool = True):
workspace_id = workspace_name_id

workspace_name = workspace_name_id
self.__cv_client.api.workspace_config(workspace_id, workspace_name)
try:
self.__cv_client.api.workspace_config(workspace_id, workspace_name)
except CvpRequestError:
MODULE_LOGGER.info('Workspace creation failed. User is unauthorized!')
self.__ansible.fail_json(msg='Workspace creation failed. User is unauthorized!')

# create tags and assign tags
for per_device in tags:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,15 @@ def tasker(self, taskIds_list: list, state: str = 'executed'):
api_result = CvApiResult(action_name='task_' + str(task_id))
if self.is_actionable(task_data=self.__get_task_data(task_id)):
if self.__ansible.check_mode is False:
self.__cv_client.api.add_note_to_task(task_id, "Executed by Ansible")
try:
self.__cv_client.api.add_note_to_task(task_id, "Executed by Ansible")
except CvpRequestError as e:
if "Forbidden" in str(e):
message = "Error while adding note and executing task. User is unauthorized!"
else:
message = "Error while adding note to task: {0}".format(str(e))
logging.error(message)
self.__ansible.fail_json(msg=message)
if state == "executed":
api_result.add_entry(self.execute_task(task_id))
api_result.changed = True
Expand Down
7 changes: 5 additions & 2 deletions ansible_collections/arista/cvp/plugins/modules/cv_facts_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,11 @@ def main():

# Instantiate ansible results
facts_collector = CvFactsTools(cv_connection=cv_client)
facts = facts_collector.facts(scope=ansible_module.params['facts'], regex_filter=ansible_module.params['regexp_filter'],
verbose=ansible_module.params['verbose'])
try:
facts = facts_collector.facts(scope=ansible_module.params['facts'], regex_filter=ansible_module.params['regexp_filter'],
verbose=ansible_module.params['verbose'])
except CvpClientError as e:
ansible_module.fail_json(msg=str(e))
result = dict(changed=False, data=facts, failed=False)

# Implement logic
Expand Down

0 comments on commit 290363f

Please sign in to comment.