Skip to content

Commit

Permalink
New swim workflow feature (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
madhansansel authored Dec 10, 2024
2 parents 38c49fa + 95bca51 commit 2de3c0d
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 106 deletions.
118 changes: 87 additions & 31 deletions plugins/modules/swim_workflow_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1666,38 +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", "")

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

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)

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
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
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):
Expand Down Expand Up @@ -2315,6 +2335,42 @@ def verify_diff_merged(self, config):

return 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:
- 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)
skipped_images_str = ", ".join(self.existing_images)

messages = []

if skipped_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))

elif not skipped_images_str:
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
Expand Down Expand Up @@ -2361,7 +2417,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_swim_profile_messages()
module.exit_json(**ccc_swims.result)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
Expand Down Expand Up @@ -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 #
#############################################
Expand All @@ -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 #
#############################################
Expand Down

0 comments on commit 2de3c0d

Please sign in to comment.