Skip to content

Commit

Permalink
ImageStage: Leverage RestSend(), more...
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
allenrobel committed Jan 31, 2024
1 parent 6bc8074 commit deb31c6
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 51 deletions.
61 changes: 21 additions & 40 deletions plugins/module_utils/image_mgmt/image_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):
"""
Expand Down
12 changes: 12 additions & 0 deletions plugins/module_utils/image_mgmt/image_upgrade_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
"""
Expand Down
6 changes: 4 additions & 2 deletions plugins/modules/dcnm_image_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand All @@ -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:
Expand All @@ -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)

Expand All @@ -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"

Expand Down Expand Up @@ -321,16 +326,17 @@ 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)

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()
Expand Down

0 comments on commit deb31c6

Please sign in to comment.