Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 162 additions & 19 deletions plugins/modules/swim_workflow_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@
description: Specify the name of the device
family such as Switches and Hubs, etc.
type: str
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name "api_task_timeout" may get confused with the existing global dnac_api_task_timeout parameter. Please note that the parameter name should reflect its specific operation scope.

Can we say

distribution_task_timeout:
    Timeout duration in seconds specifically for SWIM image distribution operations.
    Controls how long the system waits for distribution tasks to complete.... 
  
activation_task_timeout:
    Timeout duration in seconds specifically for SWIM image activation operations.
    Controls how long the system waits for activation tasks to complete.....

OR

swim_operation_timeout:
    Timeout duration in seconds for SWIM operations (distribution/activation)..
    Overrides the global dnac_api_task_timeout for SWIM-specific tasks...........

OR

image_distribution_timeout. .. image_activation_timeout ...
Check with @DNACENSolutions and update...

type: int
default: 1800

api_task_timeout:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a) Can we say what is the difference b/w global timeout and this value?
b) In document you mentioned as default of 2400 seconds but that is not true. Instead can you put in recommendations?
c) Add the version when do we start to support it..

Check the sample snippet and update if required.. Also get approval from @DNACENSolutions

api_task_timeout:
  description: |
    Timeout duration in seconds for image distribution API operations.
    Controls how long the system waits for image distribution tasks to complete,
    including image transfer to target devices, network propagation, and distribution validation.
    
    Operation phases covered by this timeout:
    - Image preparation and validation on Catalyst Center
    - Network transfer to target devices
    - Installation verification on target devices
    - Distribution status confirmation
    
    Default of 1800 seconds (30 minutes) accounts for:
    - Large image files (up to several GB)
    - Multiple target devices in site-based operations  
    - Network latency and bandwidth constraints
    - Device processing and storage capabilities
    
    Recommended timeout values:
    - Small networks (1-10 devices): 900-1800 seconds
    - Medium networks (10-50 devices): 1800-3600 seconds
    - Large networks (50+ devices): 3600-7200 seconds
    
    Note: This timeout is independent of the global 'dnac_api_task_timeout' parameter
    and specifically applies to distribution operations only.
  type: int
  default: 1800
  version_added: ?????? 

description: |
Timeout duration in seconds for image distribution API operations. Controls how long
the system waits for image distribution tasks to complete, including image transfer
to target devices, network propagation, and distribution validation. Default of 2400
seconds (40 minutes) accounts for large image files, multiple target devices, and
network latency. Adjust based on distribution scope, network bandwidth, and image size.
type: int
default: 1800
site_name:
description: Used to get device details
associated to this site.
Expand Down Expand Up @@ -467,6 +476,15 @@
ACCESS, BORDER ROUTER, DISTRIBUTION, and
CORE.
type: str
api_task_timeout:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api_task_timeout:
  description: |
    Timeout duration in seconds for image activation API operations.
    Controls how long the system waits for image activation processes to complete
    before timing out, including device reboot and startup verification.
    
    Operation phases covered by this timeout:
    - Image validation and preparation for activation
    - Device upgrade mode processing (install/bundle/currentlyExists)
    - Device reboot and startup sequence (if required)
    - Post-activation connectivity and status verification
    - Golden image validation (if applicable)
    
    Default of 1800 seconds (30 minutes) accommodates:
    - Device boot time variations (switches: 5-15 min, routers: 10-20 min)
    - Image installation and verification processes
    - Network convergence and connectivity restoration
    - Multiple devices in concurrent activation scenarios
    
    Recommended timeout values by device type:
    - Access switches: 1200-1800 seconds (20-30 minutes)
    - Distribution/Core switches: 1800-2700 seconds (30-45 minutes)
    - Routers and complex devices: 2700-3600 seconds (45-60 minutes)
    
    Warning: Setting timeout too low may cause premature failure reporting
    for successful but slow activation processes.
  type: int
  default: 1800
  version_added: ??????

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would ike the name api_task_timeout to be changed, it should be named for the activity it is addressing to. i.e. image_activation_timeout and image_distribution_timeout, both should be provided to user so they can individually plan to timeouts correctly. For example distribution on slow. network may take1Hr or more, activation will very based on if the device is a stack and and may vary from 10 mins to 30 minutes.

description: |
Timeout duration in seconds for image activation API operations. Controls how long
the system waits for image upload, installation, and activation processes to complete
before timing out. Default of 2400 seconds (40 minutes) accommodates large image
transfers and device processing time. Adjust based on network speed, image size,
and device capabilities.
type: int
default: 1800
device_family_name:
description: Specify the name of the device
family such as Switches and Hubs, etc.
Expand Down Expand Up @@ -831,6 +849,7 @@
device_family_name: Switches and Hubs
device_series_name: Cisco Catalyst 9300 Series
Switches

- name: Activate the given image on devices associated
to that site with specified role.
cisco.dnac.swim_workflow_manager:
Expand All @@ -850,7 +869,52 @@
device_role: ALL
device_family_name: Switches and Hubs
device_series_name: Cisco Catalyst 9300 Series Switches
scehdule_validate: false
schedule_validate: false
activate_lower_image_version: true
distribute_if_needed: true

- name: Activate the golden image on devices associated
to that site with specified role.
cisco.dnac.swim_workflow_manager:
dnac_host: "{{dnac_host}}"
dnac_username: "{{dnac_username}}"
dnac_password: "{{dnac_password}}"
dnac_verify: "{{dnac_verify}}"
dnac_port: "{{dnac_port}}"
dnac_version: "{{dnac_version}}"
dnac_debug: "{{dnac_debug}}"
dnac_log_level: "{{dnac_log_level}}"
dnac_log: true
config:
- image_activation_details:
site_name: Global/USA/San Francisco/BGL_18
device_role: ALL
device_family_name: Switches and Hubs
device_series_name: Cisco Catalyst 9300 Series Switches
schedule_validate: false
activate_lower_image_version: true
distribute_if_needed: true

- name: distribute the golden image on devices associated
to that site with specified role with custom api timeout.
cisco.dnac.swim_workflow_manager:
dnac_host: "{{dnac_host}}"
dnac_username: "{{dnac_username}}"
dnac_password: "{{dnac_password}}"
dnac_verify: "{{dnac_verify}}"
dnac_port: "{{dnac_port}}"
dnac_version: "{{dnac_version}}"
dnac_debug: "{{dnac_debug}}"
dnac_log_level: "{{dnac_log_level}}"
dnac_log: true
config:
- image_activation_details:
site_name: Global/USA/San Francisco/BGL_18
api_task_timeout: 2500
device_role: ALL
device_family_name: Switches and Hubs
device_series_name: Cisco Catalyst 9300 Series Switches
schedule_validate: false
activate_lower_image_version: true
distribute_if_needed: true

Expand Down Expand Up @@ -1365,11 +1429,18 @@ def get_device_uuids(
device_uuid_list = []
device_id_list, site_response_list = [], []
if not site_name:
site_names = "Global/.*"
self.log(
"Site name not specified; defaulting to 'Global' to fetch all devices under this category",
"INFO",
)
if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

current_version = self.get_ccc_version()
if self.compare_dnac_versions(current_version, "2.3.5.3") <= 0:
    site_name = "Global/.*"
    self.log(
        "Catalyst Center version {0} (≤2.3.5.3) detected - using wildcard pattern 'Global/.*' "
        "to fetch devices from Global site and all child sites via legacy API".format(current_version),
        "INFO",
    )
else:
    site_name = "Global"
    self.log(
        "Catalyst Center version {0} (>2.3.5.3) detected - using 'Global' site name "
        "to fetch devices via enhanced site hierarchy API".format(current_version),
        "INFO",
    )

site_name = "Global/.*"
self.log(
"Site name not specified; defaulting to 'Global/.*' to fetch all devices under this category",
"INFO",
)
else:
site_name = "Global"
self.log(
"Site name not specified; defaulting to 'Global' to fetch all devices under this category",
"INFO",
)

(site_exists, site_id) = self.site_exists(site_name)
if not site_exists:
Expand Down Expand Up @@ -1428,7 +1499,11 @@ def get_device_uuids(
for item_dict in item["response"]:
site_response_list.append(item_dict)
else:
self.log(site_name, "DEBUG")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't print the variable name directly. We instructed this many times in Code review.

if site_name:
self.log(
"Fetching devices for site '{0}'".format(site_name), "DEBUG"
)
site_type = self.get_sites_type(site_name)
self.log("Determined site type: {0}".format(site_type), "DEBUG")
site_info = {}
Expand Down Expand Up @@ -1493,7 +1568,7 @@ def get_device_uuids(
self.log("No child site data found under: {0}".format(wildcard_site_name), "DEBUG")
site_names = site_name

elif site_type == "area":
elif site_type in ["area", "global"]:
self.log(
"Processing site as an area: {site_name}".format(site_name=site_name),
"DEBUG",
Expand Down Expand Up @@ -1528,7 +1603,7 @@ def get_device_uuids(
"ERROR",
)

if site_type in ["area", "floor"]:
if site_type in ["area", "floor", "global"]:
self.log("Fetching site names for pattern: {0}".format(site_names), "DEBUG")
get_site_names = self.get_site(site_names)
self.log("Fetched site names: {0}".format(str(get_site_names)), "DEBUG")
Expand Down Expand Up @@ -2999,7 +3074,7 @@ def get_diff_distribution(self):
device_family = distribution_details.get("device_family_name")
device_role = distribution_details.get("device_role", "ALL")
device_series_name = distribution_details.get("device_series_name")

self.max_timeout = distribution_details.get("api_task_timeout", 1800)
self.log(
"Fetching device UUIDs for site '{0}', family '{1}', role '{2}', and series '{3}'.".format(
site_name, device_family, device_role, device_series_name
Expand Down Expand Up @@ -3087,6 +3162,7 @@ def get_diff_distribution(self):
)
self.set_operation_result("success", False, self.msg, "INFO")
return self

if (
self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.9")
<= 0
Expand Down Expand Up @@ -3213,7 +3289,7 @@ def get_diff_distribution(self):
"DEBUG",
)

self.check_tasks_response_status(
self.check_swim_tasks_response_status(
response, "distribute_images_on_the_network_device"
)

Expand Down Expand Up @@ -3401,7 +3477,7 @@ def get_diff_distribution(self):

self.log("API response from 'bulk_distribute_images_on_network_devices': {0}".format(str(response)), "DEBUG")

self.check_tasks_response_status(
self.check_swim_tasks_response_status(
response, "bulk_distribute_images_on_network_devices"
)

Expand Down Expand Up @@ -3559,6 +3635,7 @@ def get_diff_activation(self):
device_family = activation_details.get("device_family_name")
device_role = activation_details.get("device_role", "ALL")
device_series_name = activation_details.get("device_series_name")
self.max_timeout = activation_details.get("api_task_timeout", 1800)

self.log(
"Fetching device UUIDs for site '{0}', family '{1}', role '{2}', and series '{3}'.".format(
Expand Down Expand Up @@ -3653,7 +3730,7 @@ def get_diff_activation(self):
activation_payload_list = []

# OLD FLOW (for DNAC < 2.3.7.9)
if self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.9") < 0:
if self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.9") <= 0:
for image_name, image_id in image_ids.items():
payload = [
{
Expand Down Expand Up @@ -3715,7 +3792,7 @@ def get_diff_activation(self):
self.log(failed_msg, "ERROR")
break

# NEW FLOW (for Catalyst Center >= 2.3.7.9)
# NEW FLOW (for Catalyst Center > 2.3.7.9)
else:
self.log("Using new SWIM API for image activation (after 2.3.7.9)", "INFO")

Expand Down Expand Up @@ -3751,7 +3828,7 @@ def get_diff_activation(self):
)

self.log("API response from 'update_images_on_the_network_device': {0}".format(str(response)), "DEBUG")
self.check_tasks_response_status(response, "update_images_on_the_network_device")
self.check_swim_tasks_response_status(response, "update_images_on_the_network_device")

device_ip = self.get_device_ip_from_id(activation_device_id)
if response and self.status not in ["failed", "exited"]:
Expand Down Expand Up @@ -3816,8 +3893,8 @@ def get_diff_activation(self):
elg_device_list = []
device_ip_for_not_elg_list = []

# OLD FLOW (for DNAC < 2.3.7.9)
if self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.9") < 0:
# OLD FLOW (for DNAC <= 2.3.7.9)
if self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.9") <= 0:
for device_uuid in device_uuid_list:
device_ip = self.get_device_ip_from_id(device_uuid)
activated = False
Expand Down Expand Up @@ -3903,7 +3980,7 @@ def get_diff_activation(self):
"{} to {}".format(img, ", ".join(devices)) for img, devices in failed_image_map.items()
]

# NEW FLOW (for DNAC >= 2.3.7.9)
# NEW FLOW (for DNAC > 2.3.7.9)
else:
image_id_base = self.have.get("activation_image_id")
# Resolve sub-package ids (if any)
Expand All @@ -3914,7 +3991,6 @@ def get_diff_activation(self):

for device_uuid in device_uuid_list:
device_ip = self.get_device_ip_from_id(device_uuid)
device_ips.append(device_ip)
self.log("Processing device: {0}".format(device_ip), "DEBUG")

# Aggregate all image ids for this device
Expand All @@ -3934,6 +4010,8 @@ def get_diff_activation(self):
device_ip_for_not_elg_list.append(device_ip)
continue

device_ips.append(elg_device_ip)

activation_payload = {}
if device_id:
activation_payload["id"] = device_id
Expand Down Expand Up @@ -3968,7 +4046,7 @@ def get_diff_activation(self):
params={"payload": activation_payload_list},
)
self.log("API response from 'bulk_update_images_on_network_devices': {0}".format(str(response)), "DEBUG")
self.check_tasks_response_status(response, "bulk_update_images_on_network_devices")
self.check_swim_tasks_response_status(response, "bulk_update_images_on_network_devices")

if response and self.status not in ["failed", "exited"]:
self.msg = "All eligible images activated successfully on the devices {0}.".format(", ".join(device_ips))
Expand Down Expand Up @@ -4014,6 +4092,71 @@ def get_diff_activation(self):
self.complete_successful_activation = True
return self

def check_swim_tasks_response_status(self, response, api_name):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we add operation_details as well?

def check_swim_tasks_response_status(self, response, api_name, operation_details=None):

"""
Get the task response status from taskId
Args:
self: The current object details.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Args:
    self (object): An instance of a class used for interacting with Cisco Catalyst Center.
    response (dict): API response containing task information from SWIM operations.
    api_name (str): Name of the API operation being monitored for logging context.
    operation_details (dict, optional): Operation configuration for timeout determination.
    
Returns:
    self (object): Updated instance with task execution results and status information.
    
Description:
    Monitors SWIM task execution by polling the 'get_tasks_by_id' function until the task
    reaches SUCCESS or FAILURE state, or until the maximum timeout is exceeded. Uses
    operation-specific timeouts when available, falling back to global or default values.
    Handles error conditions, timeout scenarios, and provides detailed logging throughout
    the monitoring process.

response (dict): API response.
api_name (str): API name.
Returns:
self (object): The current object with updated desired Fabric Transits information.
Description:
Poll the function 'get_tasks_by_id' until it returns either 'SUCCESS' or 'FAILURE'
state or till it reaches the maximum timeout.
Log the task details and return self.
"""

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.log("Starting SWIM task status monitoring for API operation: {0}".format(api_name), "DEBUG")
self.log("Input response: {0}".format(response), "DEBUG")
self.log("Operation details for timeout calculation: {0}".format(operation_details), "DEBUG")

if not response:
self.msg = "response is empty"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a detailed message..

self.msg = "Empty response received from API '{0}' - cannot monitor task status".format(api_name)

self.status = "exited"
return self

if not isinstance(response, dict):
self.msg = "response is not a dictionary"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    self.msg = "Invalid response format from API '{0}' - expected dictionary, got {1}".format(
        api_name, type(response).__name__
    )

self.status = "exited"
return self

task_info = response.get("response")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first check the task_info, if not then return..

task_info = response.get("response")
if not task_info:
    self.msg = "Missing task information in response from API '{0}'".format(api_name)
    self.log(self.msg, "ERROR")
    self.status = "failed"
    return self

if task_info.get("errorcode") is not None:
    error_detail = task_info.get("detail", "Unknown error occurred")
    self.msg = "API '{0}' returned error: {1}".format(api_name, error_detail)
    self.log(self.msg, "ERROR")
    self.status = "failed"
    return self

if task_info.get("errorcode") is not None:
self.msg = response.get("response").get("detail")
self.status = "failed"
return self

task_id = task_info.get("taskId")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if task_id is none, then return??

if not task_id:
    self.msg = "Missing taskId in response from API '{0}'".format(api_name)
    self.log(self.msg, "ERROR")
    self.status = "failed"
    return self

start_time = time.time()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is good to determine the timeout for this operation..

# Determine appropriate timeout for this operation
if operation_details:
    operation_type = api_name.lower().replace("trigger_software_image_", "").replace("_", "")
    max_timeout = self.get_operation_timeout(operation_type, operation_details)
else:
    max_timeout = getattr(self, 'max_timeout', self.params.get("dnac_api_task_timeout", 1800))

poll_interval = self.params.get("dnac_task_poll_interval", 2)

self.log(
    "Monitoring task '{0}' from API '{1}' with timeout {2}s and poll interval {3}s".format(
        task_id, api_name, max_timeout, poll_interval
    ), 
    "INFO"
)

start_time = time.time()
task_status_history = []

while True:
    elapsed_time = time.time() - start_time

while True:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a sample code to check the task_status.. But you can refine and update if required..

    task_status_history = []

    while True:
        elapsed_time = time.time() - start_time
        
        # Check for timeout
        if elapsed_time >= max_timeout:
            self.msg = (
                "Timeout of {0} seconds reached for task '{1}' from API '{2}'. "
                "Task may still be running on Catalyst Center. "
                "Consider increasing timeout or checking task status manually."
            ).format(max_timeout, task_id, api_name)
            self.log(self.msg, "WARNING")
            self.status = "failed"
            break

        # Get current task status
        try:
            task_details = self.get_tasks_by_id(task_id)
            self.log(
                "Retrieved task details for ID '{0}': {1}".format(task_id, task_details), 
                "DEBUG"
            )
        except Exception as e:
            self.msg = "Failed to retrieve task details for ID '{0}': {1}".format(task_id, str(e))
            self.log(self.msg, "ERROR")
            self.status = "failed"
            break

        if not task_details:
            self.log(
                "Empty task details received for ID '{0}', retrying...".format(task_id), 
                "WARNING"
            )
            time.sleep(poll_interval)
            continue

        task_status = task_details.get("status", "UNKNOWN")
        
        # Track status changes for debugging
        if not task_status_history or task_status_history[-1] != task_status:
            task_status_history.append(task_status)
            self.log(
                "Task '{0}' status changed to: {1} (elapsed: {2:.1f}s)".format(
                    task_id, task_status, elapsed_time
                ), 
                "INFO"
            )

        # Handle terminal states
        if task_status == "FAILURE":
            try:
                failure_details = self.get_task_details_by_id(task_id)
                failure_reason = failure_details.get("failureReason", "Unknown failure reason")
                self.msg = "Task '{0}' from API '{1}' failed: {2}".format(
                    task_id, api_name, failure_reason
                )
                self.log(self.msg, "ERROR")
            except Exception as e:
                self.msg = "Task '{0}' failed and unable to retrieve failure details: {1}".format(
                    task_id, str(e)
                )
                self.log(self.msg, "ERROR")
            
            self.status = "failed"
            break

        elif task_status == "SUCCESS":
            self.result["changed"] = True
            self.msg = "Task '{0}' from API '{1}' completed successfully in {2:.1f} seconds".format(
                task_id, api_name, elapsed_time
            )
            self.log(self.msg, "INFO")
            self.status = "success"
            break

        # Handle unknown/unexpected status
        elif task_status not in ["IN_PROGRESS", "PENDING", "RUNNING"]:
            self.log(
                "Unexpected task status '{0}' for task '{1}'. Continuing to monitor...".format(
                    task_status, task_id
                ), 
                "WARNING"
            )
            
        # Log periodic progress updates
        if int(elapsed_time) % 30 == 0 and elapsed_time > 0:  # Every 30 seconds
            progress_info = task_details.get("progress", "No progress information")
            self.log(
                "Task '{0}' progress update: {1} (status: {2}, elapsed: {3:.1f}s)".format(
                    task_id, progress_info, task_status, elapsed_time
                ), 
                "DEBUG"
            )

        time.sleep(poll_interval)

    # Log final task monitoring summary
    self.log(
        "Task monitoring completed for '{0}'. Final status: {1}, Total time: {2:.1f}s, Status history: {3}".format(
            task_id, self.status, time.time() - start_time, " -> ".join(task_status_history)
        ), 
        "INFO"
    )
        

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def get_operation_timeout(self, operation_type, operation_details):
    """
    Get the appropriate timeout value for specific SWIM operations.
    
    Args:
        operation_type (str): Type of operation ('distribution' or 'activation')
        operation_details (dict): Operation configuration details
        
    Returns:
        int: Timeout value in seconds
    """
    self.log("Determining timeout for {0} operation".format(operation_type), "DEBUG")
    
    # Map operation types to their specific timeout parameter names
    timeout_key_mapping = {
        "distribution": "distribution_task_timeout",  # Recommended name... Check and update the name
        "activation": "activation_task_timeout"       # Recommended name.... Check and update the name
    }
    
    # Get operation-specific timeout if provided
    timeout_key = timeout_key_mapping.get(operation_type)
    if timeout_key and timeout_key in operation_details:
        operation_timeout = operation_details[timeout_key]
        self.log(
            "Using operation-specific {0}: {1} seconds for {2}".format(
                timeout_key, operation_timeout, operation_type
            ), 
            "INFO"
        )
        return operation_timeout
    
    # Fallback to global timeout
    global_timeout = self.params.get("dnac_api_task_timeout", 1800)  # Correct global name
    self.log(
        "Using global dnac_api_task_timeout: {0} seconds for {1}".format(
            global_timeout, operation_type
        ),
        "INFO"
    )
    return global_timeout

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 '{0}' status.".format(api_name)
self.log(self.msg, "WARNING")
self.status = "failed"
break

task_details = self.get_tasks_by_id(task_id)
self.log('Getting tasks details from task ID {0}: {1}'
.format(task_id, task_details), "DEBUG")

task_status = task_details.get("status")
if task_status == "FAILURE":
details = self.get_task_details_by_id(task_id)
self.msg = details.get("failureReason")
self.status = "failed"
break

elif task_status == "SUCCESS":
self.result["changed"] = True
self.log("The task with task ID '{0}' is executed successfully."
.format(task_id), "INFO")
break

self.log("Progress is {0} for task ID: {1}"
.format(task_status, task_id), "DEBUG")

return self

def get_diff_merged(self, config):
"""
Get tagging details and then trigger distribution followed by activation if specified in the playbook.
Expand Down
Loading
Loading