Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swim bug fixed #437

2 changes: 1 addition & 1 deletion plugins/modules/inventory_workflow_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1830,7 +1830,7 @@ def provision_wired_device_v2(self, device_ip, site_name):

assign_params = {'deviceIds': [device_id], 'siteId': site_id}
provision_params = [{"siteId": site_id, "networkDeviceId": device_id}]
is_device_provisioned = self.is_device_provisioned(device_id)
is_device_provisioned = self.is_device_provisioned(device_id, device_ip)
is_device_assigned_to_site = self.is_device_assigned_to_site(device_id)

if not is_device_assigned_to_site:
Expand Down
175 changes: 124 additions & 51 deletions plugins/modules/swim_workflow_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@
type: bool
image_distribution_details:
description: Details for SWIM image distribution. Device on which the image needs to distributed
Copy link
Owner

Choose a reason for hiding this comment

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

image_distribution_details:
  description: |
    Parameters for specifying the target device(s) for SWIM image distribution. The device can be identified using one of the following options:
    - device_serial_number
    - device_ip_address
    - device_hostname
    - device_mac_address
    - site_name (if specified, the image will be distributed to all devices within the site)
    
        At least one of these parameters must be provided. If 'site_name' is provided, additional filters—such as 'device_role', 'device_family_name', and 'device_series_name'—can be used to further narrow down the devices within the site.

can be speciifed using any of the following parameters - deviceSerialNumber,
deviceIPAddress, deviceHostname or deviceMacAddress.
can be speciifed using any of the following parameters - device_serial_number or
device_ip_address or device_hostname or device_mac_address or site_name
type: dict
suboptions:
device_role:
Expand Down Expand Up @@ -256,8 +256,8 @@
type: str
image_activation_details:
description: Details for SWIM image activation. Device on which the image needs to activated
Copy link
Owner

Choose a reason for hiding this comment

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

Same as like distribution

can be speciifed using any of the following parameters - deviceSerialNumber,
deviceIPAddress, deviceHostname or deviceMacAddress.
can be speciifed using any of the following parameters - device_serial_number or
device_ip_address or device_hostname or device_mac_address or site_name
type: dict
suboptions:
device_role:
Expand Down Expand Up @@ -803,31 +803,46 @@ def get_device_id(self, params):
self (object): An instance of a class used for interacting with Cisco Catalyst Center.
params (dict): A dictionary containing parameters to filter devices.
Returns:
str: The unique device ID corresponding to the filtered device.
str or None: The unique device ID corresponding to the filtered device, or None if an error occurs.
Raises:
AnsibleFailJson: If the device ID cannot be found in the response.
Description:
This function sends a request to Cisco Catalyst Center to retrieve a list of devices based on the provided
filtering parameters. If a single matching device is found, it extracts and returns the device ID. If
no device or multiple devices match the criteria, it raises an exception.
madhansansel marked this conversation as resolved.
Show resolved Hide resolved
"""
device_id = None
response = self.dnac._exec(
family="devices",
function='get_device_list',
op_modifies=True,
params=params,
)
self.log("Received API response from 'get_device_list': {0}".format(str(response)), "DEBUG")
try:
response = self.dnac._exec(
family="devices",
function='get_device_list',
op_modifies=True,
params=params,
)
self.log("Received API response from 'get_device_list': {0}".format(str(response)), "DEBUG")

device_list = response.get("response")
device_list = response.get("response")

if (len(device_list) == 1):
device_id = device_list[0].get("id")
self.log("Device Id: {0}".format(str(device_id)), "INFO")
else:
self.msg = "Device with params: '{0}' not found in Cisco Catalyst Center so can't fetch the device id".format(str(params))
self.log(self.msg, "WARNING")
if not device_list:
self.log("Device list is empty; no devices found for given parameters.", "WARNING")
raise ValueError("No devices found")

if len(device_list) == 1:
device_id = device_list[0].get("id")
self.log("Successfully retrieved device ID: {0}".format(device_id), "INFO")
return device_id

return device_id
self.log("Multiple devices found for parameters: {0}".format(params), "ERROR")
raise ValueError("Multiple devices found")

except ValueError as ve:
msg = "Error: {0}. Unable to fetch unique device ID with parameters: {1}".format(str(ve), params)
self.log(msg, "ERROR")
return None

except Exception as e:
msg = "An unexpected error occurred while retrieving device ID: {0}".format(str(e))
self.log(msg, "ERROR")
return None

def get_device_uuids(self, site_name, device_family, device_role, device_series_name=None):
"""
Expand Down Expand Up @@ -1138,16 +1153,33 @@ def get_have(self):
self.log("Image details required for distribution have not been provided", "ERROR")
self.module.fail_json(msg="Image details required for distribution have not been provided", response=[])

device_params = dict(
hostname=distribution_details.get("device_hostname"),
serialNumber=distribution_details.get("device_serial_number"),
managementIpAddress=distribution_details.get("device_ip_address"),
macAddress=distribution_details.get("device_mac_address"),
)
device_id = self.get_device_id(device_params)
device_params = {
"hostname": distribution_details.get("device_hostname"),
"serialNumber": distribution_details.get("device_serial_number"),
"managementIpAddress": distribution_details.get("device_ip_address"),
"macAddress": distribution_details.get("device_mac_address")
}

if any(device_params.values()):
device_id = self.get_device_id(device_params)

if device_id is None:
params_list = []
for key, value in device_params.items():
if value:
formatted_param = "{0}: {1}".format(key, value)
params_list.append(formatted_param)

params_message = ", ".join(params_list)
self.status = "failed"
self.msg = "The device with the following parameter(s): {0} could not be found in the Cisco Catalyst Center.".format(params_message)
self.log(self.msg, "ERROR")
self.result['response'] = self.msg
self.check_return_status()

if device_id is not None:
have["distribution_device_id"] = device_id
else:
self.log("Device with ID {0} found and added to distribution details.".format(device_id), "DEBUG")
have["distribution_device_id"] = device_id

self.have.update(have)

Expand All @@ -1174,18 +1206,41 @@ def get_have(self):
have["site_id"] = site_id
self.log("The site '{0}' exists and has the site ID '{1}'".format(site_name, str(site_id)), "INFO")

device_params = dict(
hostname=activation_details.get("device_hostname"),
serialNumber=activation_details.get("device_serial_number"),
managementIpAddress=activation_details.get("device_ip_address"),
macAddress=activation_details.get("device_mac_address"),
)
device_id = self.get_device_id(device_params)
device_params = {
"hostname": activation_details.get("device_hostname"),
"serialNumber": activation_details.get("device_serial_number"),
"managementIpAddress": activation_details.get("device_ip_address"),
"macAddress": activation_details.get("device_mac_address")
}

# Check if any device parameters are provided
if any(device_params.values()):
device_id = self.get_device_id(device_params)

if device_id is None:
desired_keys = {"hostname", "serialNumber", "managementIpAddress", "macAddress"}
params_list = []

# Format only the parameters that are present
for key, value in device_params.items():
if value and key in desired_keys:
formatted_param = "{0}: {1}".format(key, value)
params_list.append(formatted_param)

params_message = ", ".join(params_list)
self.status = "failed"
self.msg = "The device with the following parameter(s): {0} could not be found in the Cisco Catalyst Center.".format(params_message)
self.log(self.msg, "ERROR")
self.result['response'] = self.msg
self.check_return_status()

else:
have["activation_device_id"] = device_id
self.log("Device with ID {0} found and added to activation details.".format(device_id), "DEBUG")

if device_id is not None:
have["activation_device_id"] = device_id
self.have.update(have)
self.log("Current State (have): {0}".format(str(self.have)), "INFO")

self.log("Current State (have): {0}".format(str(self.have)), "INFO")

return self

Expand Down Expand Up @@ -1673,8 +1728,13 @@ def get_diff_distribution(self):
self.complete_successful_distribution = False
self.partial_successful_distribution = False
self.single_device_distribution = False
distribution_device_id = self.have.get("distribution_device_id")
device_ip = self.get_device_ip_from_id(distribution_device_id)
image_name = self.want.get("distribution_details").get("image_name")

if self.have.get("distribution_device_id"):
if distribution_device_id:
self.log("Starting image distribution for device IP {0} with ID {1}, targeting software version {2}.".format(
device_ip, distribution_device_id, image_name), "INFO")
distribution_params = dict(
payload=[dict(
deviceUuid=self.have.get("distribution_device_id"),
Expand Down Expand Up @@ -1703,15 +1763,19 @@ def get_diff_distribution(self):
self.result['changed'] = True
self.status = "success"
self.single_device_distribution = True
self.result['msg'] = "Image with Id {0} Distributed Successfully".format(image_id)
self.result['response'] = self.msg
self.result['msg'] = "Image '{0}' (ID: {1}) has been successfullyyy distributed to the device with IP address {2}.".format(
image_name, image_id, device_ip)
self.result['response'] = self.result['msg']
self.log(self.result['msg'])
break

if task_details.get("isError"):
self.status = "failed"
self.msg = "Image with Id {0} Distribution Failed".format(image_id)
self.log(self.msg, "ERROR")
self.msg = "Failed to distribute image '{0}' (ID: {1}) to the device with IP address {2}.".format(
image_name, image_id, device_ip)
self.result['msg'] = self.msg
self.result['response'] = task_details
self.log(self.result['msg'])
break

self.result['response'] = task_details if task_details else response
Expand All @@ -1730,6 +1794,7 @@ def get_diff_distribution(self):
distribution_task_dict = {}

for device_uuid in device_uuid_list:
self.log("Starting distribution of image '{0}' to multiple devices.".format(image_name))
device_management_ip = self.get_device_ip_from_id(device_uuid)
distribution_params = dict(
payload=[dict(
Expand Down Expand Up @@ -1767,7 +1832,7 @@ def get_diff_distribution(self):
self.result['changed'] = True
self.status = "success"
self.partial_successful_distribution = False
self.msg = "Image with Id '{0}' Distributed and partially successfull".format(image_id)
self.msg = "Image {0} with Id '{1}' Distributed and partially successfull".format(image_name, image_id)
self.log("For device(s) {0} image Distribution gets failed".format(str(device_ips_list)), "CRITICAL")

self.result['msg'] = self.msg
Expand Down Expand Up @@ -1799,8 +1864,13 @@ def get_diff_activation(self):
self.complete_successful_activation = False
self.partial_successful_activation = False
self.single_device_activation = False
activation_device_id = self.have.get("activation_device_id")
device_ip = self.get_device_ip_from_id(activation_device_id)
image_name = self.want.get("activation_details").get("image_name")

if self.have.get("activation_device_id"):
if activation_device_id:
self.log("Starting image activation for device IP {0} with ID {1}, targeting software version {2}.".format(
device_ip, activation_device_id, image_name), "INFO")
payload = [dict(
activateLowerImageVersion=activation_details.get("activate_lower_image_version"),
deviceUpgradeMode=activation_details.get("device_upgrade_mode"),
Expand Down Expand Up @@ -1832,17 +1902,19 @@ def get_diff_activation(self):
if not task_details.get("isError") and \
("completed successfully" in task_details.get("progress")):
self.result['changed'] = True
self.result['msg'] = "Image Activated successfully"
self.result['response'] = self.msg
self.result['msg'] = "Image '{0}' (ID: {1}) has been successfully activated on the device with IP address {2}.".format(
image_name, image_id, device_ip)
self.result['response'] = self.result['msg']
self.status = "success"
self.single_device_activation = True
break

if task_details.get("isError"):
self.msg = "Activation for Image with Id '{0}' gets failed".format(image_id)
self.status = "failed"
self.msg = "Activation of image '{0}' (ID: {1}) to the device with IP address {2} has failed.".format(image_name, image_id, device_ip)
self.result['msg'] = self.msg
self.result['response'] = task_details
self.log(self.msg, "ERROR")
self.log(self.result['msg'], "ERROR")
return self

self.result['response'] = task_details if task_details else response
Expand All @@ -1861,6 +1933,7 @@ def get_diff_activation(self):
activation_task_dict = {}

for device_uuid in device_uuid_list:
self.log("Starting activation of image '{0}' to multiple devices.".format(image_name))
device_management_ip = self.get_device_ip_from_id(device_uuid)
payload = [dict(
activateLowerImageVersion=activation_details.get("activate_lower_image_version"),
Expand Down
Loading