From deb31c67354ac798151e59040dd9388e58e92d89 Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Tue, 30 Jan 2024 14:44:20 -1000 Subject: [PATCH] ImageStage: Leverage RestSend(), more... - ImageStage: remove response, response_data, result properties (inherit from ImageUpgradeCommon) - ImageStage: modify debug statements to use json.dumps for prettier output - ImageStage: Use RestSend() class - ImageUpgradeCommon: Add response_data getter/setter properties - ImageUpgradeTask: harden handling of ImageStage.response - test_image_upgrade_image_stage.py: modify unit tests to reflect the above changes --- .../module_utils/image_mgmt/image_stage.py | 61 +++++++------------ .../image_mgmt/image_upgrade_common.py | 12 ++++ plugins/modules/dcnm_image_upgrade.py | 6 +- .../test_image_upgrade_image_stage.py | 24 +++++--- 4 files changed, 52 insertions(+), 51 deletions(-) diff --git a/plugins/module_utils/image_mgmt/image_stage.py b/plugins/module_utils/image_mgmt/image_stage.py index 6bff94b9d..ab6aaecd6 100644 --- a/plugins/module_utils/image_mgmt/image_stage.py +++ b/plugins/module_utils/image_mgmt/image_stage.py @@ -30,10 +30,10 @@ ApiEndpoints from ansible_collections.cisco.dcnm.plugins.module_utils.image_mgmt.image_upgrade_common import \ ImageUpgradeCommon +from ansible_collections.cisco.dcnm.plugins.module_utils.image_mgmt.rest_send import \ + RestSend from ansible_collections.cisco.dcnm.plugins.module_utils.image_mgmt.switch_issu_details import \ SwitchIssuDetailsBySerialNumber -from ansible_collections.cisco.dcnm.plugins.module_utils.network.dcnm.dcnm import \ - dcnm_send class ImageStage(ImageUpgradeCommon): @@ -107,6 +107,7 @@ def __init__(self, module): self.log.debug("ENTERED ImageStage()") self.endpoints = ApiEndpoints() + self.rest_send = RestSend(self.module) self._init_properties() self.serial_numbers_done = set() self.controller_version = None @@ -118,9 +119,6 @@ def __init__(self, module): def _init_properties(self): # self.properties is already initialized in the parent class self.properties["serial_numbers"] = None - self.properties["response_data"] = None - self.properties["result"] = None - self.properties["response"] = None self.properties["check_interval"] = 10 # seconds self.properties["check_timeout"] = 1800 # seconds @@ -210,25 +208,32 @@ def commit(self): else: self.payload["serialNumbers"] = self.serial_numbers - self.properties["response"] = dcnm_send( - self.module, self.verb, self.path, data=json.dumps(self.payload) - ) - self.properties["result"] = self._handle_response(self.response, self.verb) + self.rest_send.verb = self.verb + self.rest_send.path = self.path + self.rest_send.payload = self.payload - msg = f"payload: {self.payload}" + self.rest_send.commit() + + self.response = self.rest_send.response_current + self.response_current = self.rest_send.response_current + self.response_data = self.response_current.get("DATA", "No Stage DATA") + + self.result = self.rest_send.result_current + self.result_current = self.rest_send.result_current + + msg = f"payload: {json.dumps(self.payload, indent=4, sort_keys=True)}" self.log.debug(msg) - msg = f"response: {self.response}" + msg = f"response: {json.dumps(self.response, indent=4, sort_keys=True)}" self.log.debug(msg) - msg = f"result: {self.result}" + msg = f"result: {json.dumps(self.result, indent=4, sort_keys=True)}" self.log.debug(msg) - if not self.result["success"]: + if not self.result_current["success"]: msg = f"{self.class_name}.{method_name}: " - msg = f"failed: {self.result}. " - msg += f"Controller response: {self.response}" + msg = f"failed: {self.result_current}. " + msg += f"Controller response: {self.response_current}" self.module.fail_json(msg, **self.failed_result) - self.properties["response_data"] = self.response.get("DATA", "No Stage DATA") self._wait_for_image_stage_to_complete() for serial_number in self.serial_numbers_done: @@ -347,30 +352,6 @@ def serial_numbers(self, value): self.module.fail_json(msg, **self.failed_result) self.properties["serial_numbers"] = value - @property - def response_data(self): - """ - Return the result of the image staging request - for serial_numbers. - - instance.serial_numbers must be set first. - """ - return self.properties.get("response_data") - - @property - def result(self): - """ - Return the POST result from the controller - """ - return self.properties.get("result") - - @property - def response(self): - """ - Return the POST response from the controller - """ - return self.properties.get("response") - @property def check_interval(self): """ diff --git a/plugins/module_utils/image_mgmt/image_upgrade_common.py b/plugins/module_utils/image_mgmt/image_upgrade_common.py index 7878e02e9..c90b15a13 100644 --- a/plugins/module_utils/image_mgmt/image_upgrade_common.py +++ b/plugins/module_utils/image_mgmt/image_upgrade_common.py @@ -59,6 +59,7 @@ def __init__(self, module): self.properties["failed"] = False self.properties["response"] = [] self.properties["response_current"] = {} + self.properties["response_data"] = [] self.properties["result"] = [] self.properties["result_current"] = {} self.properties["send_interval"] = 5 @@ -333,6 +334,17 @@ def response(self, value): self.module.fail_json(msg, **self.failed_result) self.properties["response"].append(value) + @property + def response_data(self): + """ + Return the contents of the DATA key within current_response. + """ + return self.properties.get("response_data") + + @response_data.setter + def response_data(self, value): + self.properties["response_data"].append(value) + @property def result(self): """ diff --git a/plugins/modules/dcnm_image_upgrade.py b/plugins/modules/dcnm_image_upgrade.py index 30358ca22..76dc696fe 100644 --- a/plugins/modules/dcnm_image_upgrade.py +++ b/plugins/modules/dcnm_image_upgrade.py @@ -1049,8 +1049,10 @@ def _stage_images(self, serial_numbers) -> None: instance.commit() for diff in instance.diff: self.task_result.diff_stage = copy.deepcopy(diff) - instance.response.pop("DATA", None) - self.task_result.response_stage = instance.response + for response in instance.response: + if "DATA" in response: + response.pop("DATA") + self.task_result.response_stage = copy.deepcopy(response) def _validate_images(self, serial_numbers) -> None: """ diff --git a/tests/unit/modules/dcnm/dcnm_image_upgrade/test_image_upgrade_image_stage.py b/tests/unit/modules/dcnm/dcnm_image_upgrade/test_image_upgrade_image_stage.py index 51f9e7ea7..49da259a3 100644 --- a/tests/unit/modules/dcnm/dcnm_image_upgrade/test_image_upgrade_image_stage.py +++ b/tests/unit/modules/dcnm/dcnm_image_upgrade/test_image_upgrade_image_stage.py @@ -49,6 +49,8 @@ PATCH_MODULE_UTILS = "ansible_collections.cisco.dcnm.plugins.module_utils." PATCH_IMAGE_MGMT = PATCH_MODULE_UTILS + "image_mgmt." PATCH_COMMON = PATCH_MODULE_UTILS + "common." +PATCH_IMAGE_STAGE_REST_SEND_COMMIT = PATCH_IMAGE_MGMT + "image_stage.RestSend.commit" +PATCH_IMAGE_STAGE_REST_SEND_RESULT_CURRENT = PATCH_IMAGE_MGMT + "image_stage.RestSend.result_current" DCNM_SEND_CONTROLLER_VERSION = PATCH_COMMON + "controller_version.dcnm_send" DCNM_SEND_IMAGE_STAGE = PATCH_IMAGE_MGMT + "image_stage.dcnm_send" @@ -86,9 +88,9 @@ def test_image_mgmt_stage_00002(image_stage) -> None: """ instance = image_stage assert isinstance(instance.properties, dict) - assert instance.properties.get("response_data") is None - assert instance.properties.get("response") is None - assert instance.properties.get("result") is None + assert instance.properties.get("response_data") == [] + assert instance.properties.get("response") == [] + assert instance.properties.get("result") == [] assert instance.properties.get("serial_numbers") is None assert instance.properties.get("check_interval") == 10 assert instance.properties.get("check_timeout") == 1800 @@ -232,7 +234,7 @@ def mock_dcnm_send_controller_version(*args, **kwargs) -> Dict[str, Any]: key = "test_image_mgmt_stage_00006a" return responses_controller_version(key) - def mock_dcnm_send_image_stage(*args, **kwargs) -> Dict[str, Any]: + def mock_rest_send_image_stage(*args, **kwargs) -> Dict[str, Any]: key = "test_image_mgmt_stage_00006a" return responses_image_stage(key) @@ -241,8 +243,9 @@ def mock_dcnm_send_issu_details(*args, **kwargs) -> Dict[str, Any]: return responses_switch_issu_details(key) monkeypatch.setattr(DCNM_SEND_CONTROLLER_VERSION, mock_dcnm_send_controller_version) - monkeypatch.setattr(DCNM_SEND_IMAGE_STAGE, mock_dcnm_send_image_stage) monkeypatch.setattr(DCNM_SEND_ISSU_DETAILS, mock_dcnm_send_issu_details) + monkeypatch.setattr(PATCH_IMAGE_STAGE_REST_SEND_COMMIT, mock_rest_send_image_stage) + monkeypatch.setattr(PATCH_IMAGE_STAGE_REST_SEND_RESULT_CURRENT, {"success": True}) instance = image_stage if serial_numbers_is_set: @@ -267,7 +270,7 @@ def mock_dcnm_send_controller_version(*args, **kwargs) -> Dict[str, Any]: return responses_controller_version(key) # Needed only for the 200 return code - def mock_dcnm_send_image_stage(*args, **kwargs) -> Dict[str, Any]: + def mock_rest_send_image_stage(*args, **kwargs) -> Dict[str, Any]: key = "test_image_mgmt_stage_00007a" return responses_image_stage(key) @@ -276,9 +279,11 @@ def mock_dcnm_send_issu_details(*args, **kwargs) -> Dict[str, Any]: return responses_switch_issu_details(key) monkeypatch.setattr(DCNM_SEND_CONTROLLER_VERSION, mock_dcnm_send_controller_version) - monkeypatch.setattr(DCNM_SEND_IMAGE_STAGE, mock_dcnm_send_image_stage) monkeypatch.setattr(DCNM_SEND_ISSU_DETAILS, mock_dcnm_send_issu_details) + monkeypatch.setattr(PATCH_IMAGE_STAGE_REST_SEND_COMMIT, mock_rest_send_image_stage) + monkeypatch.setattr(PATCH_IMAGE_STAGE_REST_SEND_RESULT_CURRENT, {"success": True}) + module_path = "/appcenter/cisco/ndfc/api/v1/imagemanagement/rest/" module_path += "stagingmanagement/stage-image" @@ -321,7 +326,7 @@ def mock_controller_version(*args) -> None: controller_version_patch += "ImageStage._populate_controller_version" monkeypatch.setattr(controller_version_patch, mock_controller_version) - def mock_dcnm_send_image_stage(*args, **kwargs) -> Dict[str, Any]: + def mock_rest_send_image_stage(*args, **kwargs) -> Dict[str, Any]: key = "test_image_mgmt_stage_00008a" return responses_image_stage(key) @@ -329,8 +334,9 @@ def mock_dcnm_send_issu_details(*args) -> Dict[str, Any]: key = "test_image_mgmt_stage_00008a" return responses_switch_issu_details(key) - monkeypatch.setattr(DCNM_SEND_IMAGE_STAGE, mock_dcnm_send_image_stage) monkeypatch.setattr(DCNM_SEND_ISSU_DETAILS, mock_dcnm_send_issu_details) + monkeypatch.setattr(PATCH_IMAGE_STAGE_REST_SEND_COMMIT, mock_rest_send_image_stage) + monkeypatch.setattr(PATCH_IMAGE_STAGE_REST_SEND_RESULT_CURRENT, {"success": True}) instance.serial_numbers = ["FDO21120U5D"] instance.commit()