From f0cfd71e69484be5f4e1c3082774484f44f73485 Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Mon, 9 Dec 2024 09:47:35 +0530 Subject: [PATCH 1/9] code is in progress for the SWIM bugs --- plugins/modules/swim_workflow_manager.py | 40 ++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index 94d831a60..806b57a84 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -586,6 +586,7 @@ class Swim(DnacBase): def __init__(self, module): super().__init__(module) self.supported_states = ["merged"] + self.images_to_import, self.existing_images = [], [] def validate_input(self): """ @@ -1373,6 +1374,7 @@ def get_diff_import(self): self.log(name) if self.is_image_exist(name): existing_images.append(name) + self.existing_images.append(name) self.log("Image '{0}' already exists in Cisco Catalyst Center, skipping import.".format(name), "INFO") else: images_to_import.append(name) @@ -1457,7 +1459,7 @@ def get_diff_import(self): if "completed successfully" in task_details.get("progress", "").lower(): if images_to_import: images_to_import_str = ", ".join(images_to_import) - + self.images_to_import.append(images_to_import_str) self.result['changed'] = True self.status = "success" self.msg = "Swim Image(s) {0} imported successfully".format(images_to_import_str) @@ -1679,6 +1681,13 @@ def get_diff_tagging(self): self.result['response'] = self.msg self.log(self.msg, "INFO") break + elif task_details.get("isError"): + self.status = "failed" + self.result['changed'] = False + self.msg = ("Tagging image {0} golden for site {1} for family {2} for device deviceTag" + " - {3} Failed".format(image_name, site_name, device_family, device_role)) + self.result['msg'] = self.msg + self.log(self.msg, "ERROR") else: if not task_details.get("isError") and 'successful' in task_details.get("progress"): self.status = "success" @@ -1689,6 +1698,7 @@ def get_diff_tagging(self): self.result['response'] = self.msg self.log(self.msg, "INFO") break + elif task_details.get("isError"): failure_reason = task_details.get("failureReason", "") if failure_reason and "An inheritted tag cannot be un-tagged" in failure_reason: @@ -2314,7 +2324,33 @@ def verify_diff_merged(self, config): self.verify_diff_activated().check_return_status() return self + def update_inventory_profile_messages(self): + + if self.images_to_import or self.existing_images: + imported_images_str = ", ".join(self.images_to_import) + skipped_images_str = ", ".join(self.existing_images) + + messages = [] + + if skipped_images_str: + if imported_images_str: + messages.append("Image(s) {0} were skipped as they already exist in Cisco Catalyst Center.".format(skipped_images_str)) + messages.append("Images {0} have been imported successfully.".format(imported_images_str)) + else: + messages.append("Image(s) {0} were skipped as they already exist in Cisco Catalyst Center." + "No new images were imported.".format(skipped_images_str)) + elif imported_images_str: + messages.append("Image(s) {0} have been imported successfully into Cisco Catalyst Center.".format(imported_images_str)) + else: + messages.append("No images were imported.") + self.msg = " ".join(messages) + + self.result['msg'] = self.msg + self.result['response'] = self.msg + self.log(self.msg, "INFO") + + return self def main(): """ main entry point for module execution @@ -2361,7 +2397,7 @@ def main(): ccc_swims.get_diff_state_apply[state](config).check_return_status() if config_verify: ccc_swims.verify_diff_state_apply[state](config).check_return_status() - + ccc_swims.update_inventory_profile_messages() module.exit_json(**ccc_swims.result) From 137d752fffe82a5f9fb484638ebc9a67789395f4 Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Mon, 9 Dec 2024 13:26:10 +0530 Subject: [PATCH 2/9] Swim Bug fixed --- plugins/modules/swim_workflow_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index 806b57a84..42cbf6efc 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -138,7 +138,7 @@ to import an image..(For example, http://{host}/swim/cat9k_isoxe.16.12.10s.SPA.bin, ftp://user:password@{host}/swim/cat9k_isoxe.16.12.10s.SPA.iso) type: list - elements: str + elements: List is_third_party: description: Flag indicates whether the image is uploaded from a third party (optional). type: bool @@ -1688,6 +1688,7 @@ def get_diff_tagging(self): " - {3} Failed".format(image_name, site_name, device_family, device_role)) self.result['msg'] = self.msg self.log(self.msg, "ERROR") + break else: if not task_details.get("isError") and 'successful' in task_details.get("progress"): self.status = "success" From e9e022c971d722d548fd981252329a41538576d1 Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Mon, 9 Dec 2024 18:13:37 +0530 Subject: [PATCH 3/9] swim 2 bugs fixed --- plugins/modules/swim_workflow_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index 42cbf6efc..b3d788dc4 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -1687,6 +1687,7 @@ def get_diff_tagging(self): self.msg = ("Tagging image {0} golden for site {1} for family {2} for device deviceTag" " - {3} Failed".format(image_name, site_name, device_family, device_role)) self.result['msg'] = self.msg + self.result['response'] = self.msg self.log(self.msg, "ERROR") break else: From 0c71afb7fa5496dfa73b5ce20f095164a535434c Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Mon, 9 Dec 2024 18:31:32 +0530 Subject: [PATCH 4/9] sanity fixed --- plugins/modules/swim_workflow_manager.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index b3d788dc4..5ae4e1659 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -138,7 +138,7 @@ to import an image..(For example, http://{host}/swim/cat9k_isoxe.16.12.10s.SPA.bin, ftp://user:password@{host}/swim/cat9k_isoxe.16.12.10s.SPA.iso) type: list - elements: List + elements: str is_third_party: description: Flag indicates whether the image is uploaded from a third party (optional). type: bool @@ -2326,7 +2326,19 @@ def verify_diff_merged(self, config): self.verify_diff_activated().check_return_status() return self + def update_inventory_profile_messages(self): + """ + Verify the merged status (Importing/Tagging/Distributing/Activating) of the SWIM Image in devices in Cisco Catalyst Center. + Args: + - self (object): An instance of a class used for interacting with Cisco Catalyst Center. + Return: + - self (object): An instance of a class used for interacting with Cisco Catalyst Center. + Description: + This method checks the merged status of a configuration in Cisco Catalyst Center by retrieving the current state + (have) and desired state (want) of the configuration. It logs the current and desired states, and validates whether + the specified SWIM operation (Importing, Tagging, Distributing, or Activating) has been successfully performed or not. + """ if self.images_to_import or self.existing_images: imported_images_str = ", ".join(self.images_to_import) @@ -2354,6 +2366,7 @@ def update_inventory_profile_messages(self): return self + def main(): """ main entry point for module execution """ From 97ca0900e4ea505663753c52a354b6ea720be2d2 Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Mon, 9 Dec 2024 18:41:25 +0530 Subject: [PATCH 5/9] sanity fixed --- .../tests/test_swim_management.yml | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/integration/ccc_swim_management/tests/test_swim_management.yml b/tests/integration/ccc_swim_management/tests/test_swim_management.yml index a3acfab0b..7154ba622 100644 --- a/tests/integration/ccc_swim_management/tests/test_swim_management.yml +++ b/tests/integration/ccc_swim_management/tests/test_swim_management.yml @@ -256,26 +256,26 @@ # Delete Device # ############################################# - - name: Delete device - cisco.dnac.inventory_workflow_manager: - <<: *dnac_login - state: deleted - config: - - "{{ item }}" - loop: "{{ vars_map.delete_devices }}" - register: result_device_deleted + # - name: Delete device + # cisco.dnac.inventory_workflow_manager: + # <<: *dnac_login + # state: deleted + # config: + # - "{{ item }}" + # loop: "{{ vars_map.delete_devices }}" + # register: result_device_deleted - # - name: Debug item - # debug: - # var: item - # loop: "{{ result_device_deleted.results }}" - # when: result_device_deleted is defined + # # - name: Debug item + # # debug: + # # var: item + # # loop: "{{ result_device_deleted.results }}" + # # when: result_device_deleted is defined - - name: Assert device deletion success - assert: - that: - - result_device_deleted.changed == true - when: result_device_deleted is defined + # - name: Assert device deletion success + # assert: + # that: + # - result_device_deleted.changed == true + # when: result_device_deleted is defined ############################################# # PAUSE # From 565f59e0ebd2d533edf68a2cd8e0c56fbda5fc13 Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Mon, 9 Dec 2024 18:43:12 +0530 Subject: [PATCH 6/9] sanity fixed --- plugins/modules/swim_workflow_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index 5ae4e1659..dc0275ae4 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -2327,7 +2327,7 @@ def verify_diff_merged(self, config): return self - def update_inventory_profile_messages(self): + def update_swim_profile_messages(self): """ Verify the merged status (Importing/Tagging/Distributing/Activating) of the SWIM Image in devices in Cisco Catalyst Center. Args: @@ -2412,7 +2412,7 @@ def main(): ccc_swims.get_diff_state_apply[state](config).check_return_status() if config_verify: ccc_swims.verify_diff_state_apply[state](config).check_return_status() - ccc_swims.update_inventory_profile_messages() + ccc_swims.update_swim_profile_messages() module.exit_json(**ccc_swims.result) From 607f1ef5fc48cfb86b85857cea5b06afa78d2d5d Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Tue, 10 Dec 2024 10:39:36 +0530 Subject: [PATCH 7/9] review comments compleated --- plugins/modules/swim_workflow_manager.py | 97 +++++++++++++----------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index dc0275ae4..2d25696c8 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -1668,48 +1668,56 @@ def get_diff_tagging(self): else: site_name = tagging_details.get("site_name") + start_time = time.time() + while True: task_details = self.get_task_details(task_id) + is_error = task_details.get("isError") + progress = task_details.get("progress", "") + failure_reason = task_details.get("failureReason", "") + elapsed_time = time.time() - start_time + + if elapsed_time >= self.max_timeout: + self.msg = "Max timeout of {0} sec has reached for the task id '{1}'. " \ + .format(self.max_timeout, task_id) + \ + "Exiting the loop due to unexpected API status." + self.log(self.msg, "WARNING") + self.status = "failed" + break - if tag_image_golden: - if not task_details.get("isError") and 'successful' in task_details.get("progress"): - self.status = "success" - self.result['changed'] = True - self.msg = ("Tagging image {0} golden for site {1} for family {2} for device deviceTag" - " - {3} successful".format(image_name, site_name, device_family, device_role)) - self.result['msg'] = self.msg - self.result['response'] = self.msg - self.log(self.msg, "INFO") - break - elif task_details.get("isError"): - self.status = "failed" - self.result['changed'] = False - self.msg = ("Tagging image {0} golden for site {1} for family {2} for device deviceTag" - " - {3} Failed".format(image_name, site_name, device_family, device_role)) - self.result['msg'] = self.msg - self.result['response'] = self.msg - self.log(self.msg, "ERROR") - break - else: - if not task_details.get("isError") and 'successful' in task_details.get("progress"): - self.status = "success" - self.result['changed'] = True - self.msg = ("Un-Tagging image {0} golden for site {1} for family {2} for device deviceTag" - " - {3} successful".format(image_name, site_name, device_family, device_role)) - self.result['msg'] = self.msg - self.result['response'] = self.msg - self.log(self.msg, "INFO") - break + if is_error: + if not tag_image_golden and "An inheritted tag cannot be un-tagged" in failure_reason: + self.msg = failure_reason + else: + action = "Tagging" if tag_image_golden else "Un-Tagging" + self.msg = ( + "{0} image {1} golden for site {2} for family {3} for device role {4} failed." + .format(action, image_name, site_name, device_family, device_role) + ) + self.status = "failed" + self.result['changed'] = False + self.result['msg'] = self.msg + self.result['response'] = self.msg + self.log(self.msg, "ERROR") + break + + if "successful" in progress: + action = "Tagging" if tag_image_golden else "Un-Tagging" + self.msg = ( + "{0} image {1} golden for site {2} for family {3} for device role {4} successful." + .format(action, image_name, site_name, device_family, device_role) + ) + self.status = "success" + self.result['changed'] = True + self.result['msg'] = self.msg + self.result['response'] = self.msg + self.log(self.msg, "INFO") + break + + poll_interval = self.params.get("dnac_task_poll_interval") + self.log("Waiting for the next poll interval of {0} seconds before checking task status again.".format(poll_interval), "DEBUG") + time.sleep(poll_interval) - elif task_details.get("isError"): - failure_reason = task_details.get("failureReason", "") - if failure_reason and "An inheritted tag cannot be un-tagged" in failure_reason: - self.status = "failed" - self.result['changed'] = False - self.msg = failure_reason - self.result['msg'] = failure_reason - self.log(self.msg, "ERROR") - break return self def get_device_ip_from_id(self, device_id): @@ -2347,15 +2355,12 @@ def update_swim_profile_messages(self): messages = [] if skipped_images_str: - if imported_images_str: - messages.append("Image(s) {0} were skipped as they already exist in Cisco Catalyst Center.".format(skipped_images_str)) - messages.append("Images {0} have been imported successfully.".format(imported_images_str)) - else: - messages.append("Image(s) {0} were skipped as they already exist in Cisco Catalyst Center." - "No new images were imported.".format(skipped_images_str)) - elif imported_images_str: + messages.append("Image(s) {0} were skipped as they already exist in Cisco Catalyst Center.".format(skipped_images_str)) + + if imported_images_str: messages.append("Image(s) {0} have been imported successfully into Cisco Catalyst Center.".format(imported_images_str)) - else: + + elif not skipped_images_str: messages.append("No images were imported.") self.msg = " ".join(messages) From 04b8db5b9f5d21a03bd33e238090ea5cb3ddb44b Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Tue, 10 Dec 2024 10:43:37 +0530 Subject: [PATCH 8/9] review comments compleated --- .../tests/test_swim_management.yml | 75 ------------------- 1 file changed, 75 deletions(-) diff --git a/tests/integration/ccc_swim_management/tests/test_swim_management.yml b/tests/integration/ccc_swim_management/tests/test_swim_management.yml index 7154ba622..57f94b37d 100644 --- a/tests/integration/ccc_swim_management/tests/test_swim_management.yml +++ b/tests/integration/ccc_swim_management/tests/test_swim_management.yml @@ -101,32 +101,6 @@ loop: "{{ result_add_device.results }}" when: result_add_device is defined -############################################# -# ASSOCIATE WIRED DEVICE TO SITE # -############################################# - - # - name: Assign wired device to site and then provision - # cisco.dnac.inventory_workflow_manager: - # <<: *dnac_login - # state: merged - # config: - # - "{{ item }}" - # loop: "{{ vars_map.associate_wired_device }}" - # register: result_associate_device - - # - name: Debug item - # debug: - # var: item - # loop: "{{ result_associate_device.results }}" - # when: result_associate_device is defined - - # - name: Assert Assign wired device to site and then provision - # assert: - # that: - # - item.changed == true - # loop: "{{ result_associate_device.results }}" - # when: result_associate_device is defined - ############################################# # IMPORT IMAGE # @@ -202,30 +176,6 @@ # loop: "{{ result_distribute_stack.results }}" # when: result_distribute_stack is defined -############################################# -# ACTIVATE IMAGE # -############################################# - - # - name: SWIM task - activate - # cisco.dnac.swim_workflow_manager: - # <<: *dnac_login - # config: - # - "{{ item }}" - # loop: "{{ vars_map.image_activation_details }}" - # register: result_activate_image - - # - name: Debug item - # debug: - # var: item - # loop: "{{ result_activate_image.results }}" - - # - name: Assert image activation - # assert: - # that: - # - item.changed == true - # loop: "{{ result_activate_image.results }}" - # when: result_activate_image is defined - ############################################# # UNTAG IMAGE # ############################################# @@ -252,31 +202,6 @@ loop: "{{ result_untag_image.results }}" when: result_untag_image is defined -############################################# -# Delete Device # -############################################# - - # - name: Delete device - # cisco.dnac.inventory_workflow_manager: - # <<: *dnac_login - # state: deleted - # config: - # - "{{ item }}" - # loop: "{{ vars_map.delete_devices }}" - # register: result_device_deleted - - # # - name: Debug item - # # debug: - # # var: item - # # loop: "{{ result_device_deleted.results }}" - # # when: result_device_deleted is defined - - # - name: Assert device deletion success - # assert: - # that: - # - result_device_deleted.changed == true - # when: result_device_deleted is defined - ############################################# # PAUSE # ############################################# From 95bca518fd39ca39df7594e41443830d21077332 Mon Sep 17 00:00:00 2001 From: Syed-khadeerahmed Date: Tue, 10 Dec 2024 11:11:25 +0530 Subject: [PATCH 9/9] review comments fixed --- plugins/modules/swim_workflow_manager.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/modules/swim_workflow_manager.py b/plugins/modules/swim_workflow_manager.py index 2d25696c8..1b85b8039 100644 --- a/plugins/modules/swim_workflow_manager.py +++ b/plugins/modules/swim_workflow_manager.py @@ -1675,15 +1675,6 @@ def get_diff_tagging(self): is_error = task_details.get("isError") progress = task_details.get("progress", "") failure_reason = task_details.get("failureReason", "") - elapsed_time = time.time() - start_time - - if elapsed_time >= self.max_timeout: - self.msg = "Max timeout of {0} sec has reached for the task id '{1}'. " \ - .format(self.max_timeout, task_id) + \ - "Exiting the loop due to unexpected API status." - self.log(self.msg, "WARNING") - self.status = "failed" - break if is_error: if not tag_image_golden and "An inheritted tag cannot be un-tagged" in failure_reason: @@ -1714,6 +1705,15 @@ def get_diff_tagging(self): self.log(self.msg, "INFO") break + elapsed_time = time.time() - start_time + if elapsed_time >= self.max_timeout: + self.msg = "Max timeout of {0} sec has reached for the task id '{1}'. " \ + .format(self.max_timeout, task_id) + \ + "Exiting the loop due to unexpected API status." + self.log(self.msg, "WARNING") + self.status = "failed" + break + poll_interval = self.params.get("dnac_task_poll_interval") self.log("Waiting for the next poll interval of {0} seconds before checking task status again.".format(poll_interval), "DEBUG") time.sleep(poll_interval)