From e98d330a8894ab4c136f5aea1985cfa12f7242d5 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Wed, 11 Dec 2024 01:31:28 +0530 Subject: [PATCH 01/11] Network setting delete all enhancement --- .../network_settings_workflow_manager.py | 655 ++++++++++++------ 1 file changed, 427 insertions(+), 228 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index dcc2d5ab0..388904874 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -3,7 +3,6 @@ # Copyright (c) 2024, Cisco Systems # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) - """Ansible module to perform operations on global pool, reserve pool and network in Cisco Catalyst Center.""" from __future__ import absolute_import, division, print_function @@ -15,38 +14,38 @@ module: network_settings_workflow_manager short_description: Resource module for IP Address pools and network functions description: - - Manage operations on Global Pool, Reserve Pool, Network resources. - - API to create/update/delete global pool. - - API to reserve/update/delete an ip subpool from the global pool. - - API to update network settings for DHCP, Syslog, SNMP, NTP, Network AAA, Client and Endpoint AAA, +- Manage operations on Global Pool, Reserve Pool, Network resources. +- API to create/update/delete global pool. +- API to reserve/update/delete an ip subpool from the global pool. +- API to update network settings for DHCP, Syslog, SNMP, NTP, Network AAA, Client and Endpoint AAA, and/or DNS center server settings. version_added: '6.6.0' extends_documentation_fragment: - - cisco.dnac.workflow_manager_params + - cisco.dnac.workflow_manager_params author: Muthu Rakesh (@MUTHU-RAKESH-27) Madhan Sankaranarayanan (@madhansansel) Megha Kandari (@kandarimegha) options: - config_verify: - description: Set to True to verify the Cisco Catalyst Center after applying the playbook config. - type: bool - default: False - state: - description: The state of Cisco Catalyst Center after module completion. - type: str - choices: [merged, deleted] - default: merged - config: - description: + config_verify: + description: Set to True to verify the Cisco Catalyst Center after applying the playbook config. + type: bool + default: False + state: + description: The state of Cisco Catalyst Center after module completion. + type: str + choices: [merged, deleted] + default: merged + config: + description: - List of details of global pool, reserved pool, network being managed. - type: list - elements: dict - required: true - suboptions: - global_pool_details: - description: Manages IPv4 and IPv6 IP pools in the global level. - type: dict - suboptions: + type: list + elements: dict + required: true + suboptions: + global_pool_details: + description: Manages IPv4 and IPv6 IP pools in the global level. + type: dict + suboptions: settings: description: Global Pool's settings. type: dict @@ -58,10 +57,10 @@ suboptions: name: description: - - Specifies the name assigned to the Global IP Pool. - - Required for the operations in the Global IP Pool. - - Length should be less than or equal to 100. - - Only letters, numbers and -_./ characters are allowed. + - Specifies the name assigned to the Global IP Pool. + - Required for the operations in the Global IP Pool. + - Length should be less than or equal to 100. + - Only letters, numbers and -_./ characters are allowed. type: str pool_type: description: > @@ -101,7 +100,7 @@ exclusively when you need to update the global pool's name. type: str - reserve_pool_details: + reserve_pool_details: description: Reserved IP subpool details from the global pool. type: dict suboptions: @@ -112,10 +111,10 @@ type: str name: description: - - Name of the reserve IP subpool. - - Required for the operations in the Reserve IP Pool. - - Length should be less than or equal to 100. - - Only letters, numbers and -_./ characters are allowed. + - Name of the reserve IP subpool. + - Required for the operations in the Reserve IP Pool. + - Length should be less than or equal to 100. + - Only letters, numbers and -_./ characters are allowed. type: str pool_type: description: Type of the reserve ip sub pool. @@ -140,13 +139,13 @@ type: bool ipv4_global_pool: description: - - IP v4 Global pool address with cidr, example 175.175.0.0/16. - - If both 'ipv6_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. + - IP v4 Global pool address with cidr, example 175.175.0.0/16. + - If both 'ipv6_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. type: str ipv4_global_pool_name: description: - - Specifies the name to be associated with the IPv4 Global IP Pool. - - If both 'ipv4_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. + - Specifies the name to be associated with the IPv4 Global IP Pool. + - If both 'ipv4_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. type: str version_added: 6.14.0 ipv4_subnet: @@ -192,14 +191,14 @@ type: str ipv6_global_pool: description: - - The ipv6_global_pool is a required when the ipv6_address_space is set to true. - - It specifies the global IPv6 address pool using CIDR notation, such as "2001:db8:85a3::/64". - - In cases where both ipv6_global_pool and ipv6_global_pool_name are specified, ipv6_global_pool will take precedence. + - The ipv6_global_pool is a required when the ipv6_address_space is set to true. + - It specifies the global IPv6 address pool using CIDR notation, such as "2001:db8:85a3::/64". + - In cases where both ipv6_global_pool and ipv6_global_pool_name are specified, ipv6_global_pool will take precedence. type: str ipv6_global_pool_name: description: - - Specifies the name assigned to the Ip v6 Global IP Pool. - - If both 'ipv6_global_pool' and 'ipv6_global_pool_name' are provided, the 'ipv6_global_pool' will be given priority. + - Specifies the name assigned to the Ip v6 Global IP Pool. + - If both 'ipv6_global_pool' and 'ipv6_global_pool_name' are provided, the 'ipv6_global_pool' will be given priority. type: str version_added: 6.14.0 ipv6_subnet: @@ -227,7 +226,7 @@ Allows devices on IPv6 networks to self-configure their IP addresses autonomously, eliminating the need for manual setup. type: bool - network_management_details: + network_management_details: description: Set default network settings for the site type: list elements: dict @@ -445,10 +444,10 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: merged - config_verify: True + config_verify: true config: - global_pool_details: settings: @@ -470,25 +469,25 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: merged - config_verify: True + config_verify: true config: - reserve_pool_details: - site_name: string name: string pool_type: LAN - ipv6_address_space: True + ipv6_address_space: true ipv4_global_pool: string - ipv4_prefix: True + ipv4_prefix: true ipv4_prefix_length: 9 ipv4_subnet: string - ipv6_prefix: True + ipv6_prefix: true ipv6_prefix_length: 64 ipv6_global_pool: string ipv6_subnet: string - slaac_support: True + slaac_support: true - name: Create reserve an ip pool using global pool name cisco.dnac.network_settings_workflow_manager: @@ -499,25 +498,25 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: merged - config_verify: True + config_verify: true config: - reserve_pool_details: - name: string site_name: string pool_type: LAN - ipv6_address_space: True + ipv6_address_space: true ipv4_global_pool_name: string - ipv4_prefix: True + ipv4_prefix: true ipv4_prefix_length: 9 ipv4_subnet: string - ipv6_prefix: True + ipv6_prefix: true ipv6_prefix_length: 64 ipv6_global_pool_name: string ipv6_subnet: string - slaac_support: True + slaac_support: true - name: Delete reserved pool cisco.dnac.network_settings_workflow_manager: @@ -528,10 +527,10 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: deleted - config_verify: True + config_verify: true config: - reserve_pool_details: - site_name: string @@ -565,10 +564,10 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: merged - config_verify: True + config_verify: true config: - network_management_details: - site_name: string @@ -587,10 +586,10 @@ ip_address: string port: 443 snmp_server: - configure_dnac_ip: True + configure_dnac_ip: true ip_addresses: list syslog_server: - configure_dnac_ip: True + configure_dnac_ip: true ip_addresses: list - name: Adding the network_aaa and client_and_endpoint_aaa AAA server @@ -602,10 +601,10 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: merged - config_verify: True + config_verify: true config: - network_management_details: - site_name: string @@ -630,10 +629,10 @@ dnac_port: "{{dnac_port}}" dnac_version: "{{dnac_version}}" dnac_debug: "{{dnac_debug}}" - dnac_log: True + dnac_log: true dnac_log_level: "{{ dnac_log_level }}" state: merged - config_verify: True + config_verify: true config: - network_management_details: - site_name: string @@ -751,6 +750,7 @@ def validate_input(self): "name": {"type": 'string'}, "prev_name": {"type": 'string'}, "pool_type": {"type": 'string', "choices": ["Generic", "Tunnel"]}, + 'delete_all': {'type': 'bool', 'required': False, 'default': True}, } } }, @@ -782,6 +782,7 @@ def validate_input(self): "type": 'string', "choices": ["Generic", "LAN", "Management", "Service", "WAN"] }, + 'delete_all': {'type': 'bool', 'required': False, 'default': True}, }, "network_management_details": { "type": 'list', @@ -1792,7 +1793,12 @@ def get_reserved_ip_subpool(self, site_id): return self self.all_reserved_pool_details.get(site_id).extend(reserve_pool_details) - value += 25 + + if len(reserve_pool_details) == 25: + value += 25 + else: + break + end_time = time.time() if (end_time - start_time) >= self.max_timeout: self.msg = ( @@ -1823,6 +1829,7 @@ def global_pool_exists(self, name): "details": None, "id": None } + all_global_pool = [] value = 1 while True: try: @@ -1848,21 +1855,38 @@ def global_pool_exists(self, name): all_global_pool_details = response.get("response") if not all_global_pool_details: + if name == "": + self.log("Global pool '{0}' does not exist".format(all_global_pool), "INFO") + return all_global_pool self.log("Global pool '{0}' does not exist".format(name), "INFO") return global_pool - global_pool_details = get_dict_result(all_global_pool_details, "ipPoolName", name) - if global_pool_details: + global_pool_details = None + if name == "": + global_pool_details = all_global_pool_details + else: + global_pool_details = get_dict_result(all_global_pool_details, "ipPoolName", name) + + if global_pool_details and isinstance(global_pool_details, dict): self.log("Global pool found with name '{0}': {1}".format(name, global_pool_details), "INFO") global_pool.update({"exists": True}) global_pool.update({"id": global_pool_details.get("id")}) global_pool["details"] = self.get_global_pool_params(global_pool_details) - break + self.log("Formatted global pool details: {0}".format(global_pool), "DEBUG") + return global_pool - value += 25 + if global_pool_details and isinstance(global_pool_details, list): + self.log("Global pool found {0}".format( + self.pprint(global_pool_details)), "INFO") - self.log("Formatted global pool details: {0}".format(global_pool), "DEBUG") - return global_pool + for each_pool in global_pool_details: + global_del_pool = { + "exists": True, + "id": each_pool.get("id"), + "details": self.get_global_pool_params(each_pool) + } + all_global_pool.append(global_del_pool) + value += 25 def reserve_pool_exists(self, name, site_name): """ @@ -1902,17 +1926,41 @@ def reserve_pool_exists(self, name, site_name): .format(name, site_name), "DEBUG") return reserve_pool - reserve_pool_details = get_dict_result(self.all_reserved_pool_details.get(site_id), "groupName", name) - if reserve_pool_details: - self.log("Reserve pool found with name '{0}' in the site '{1}': {2}" + reserve_pool_details = None + if name == "": + reserve_pool_details = self.all_reserved_pool_details.get(site_id) + else: + reserve_pool_details = get_dict_result( + self.all_reserved_pool_details.get(site_id), "groupName", name) + + if reserve_pool_details and isinstance(reserve_pool_details, dict): + self.log("Reserve pool found with name {0} in the site '{1}': {2}" .format(name, site_name, reserve_pool_details), "INFO") reserve_pool.update({"exists": True}) reserve_pool.update({"id": reserve_pool_details.get("id")}) reserve_pool.update({"details": self.get_reserve_pool_params(reserve_pool_details)}) + self.log("Reserved pool details: {0}".format(reserve_pool.get("details")), "DEBUG") + self.log("Reserved pool id: {0}".format(reserve_pool.get("id")), "DEBUG") + return reserve_pool - self.log("Reserved pool details: {0}".format(reserve_pool.get("details")), "DEBUG") - self.log("Reserved pool id: {0}".format(reserve_pool.get("id")), "DEBUG") - return reserve_pool + if reserve_pool_details and isinstance(reserve_pool_details, list): + self.log("Reserve pool found for the site '{0}': {1}" + .format(site_name, self.pprint(reserve_pool_details)), "INFO") + all_reserve_pool = [] + for each_pool in reserve_pool_details: + reserve_del_pool = { + "exists": True, + "id": each_pool.get("id"), + "details": self.get_reserve_pool_params(each_pool), + "success": True + } + all_reserve_pool.append(reserve_del_pool) + + self.log("Reserved pool list details: {0}".format( + self.pprint(all_reserve_pool)), "DEBUG") + return all_reserve_pool + + return None def get_have_global_pool(self, global_pool_details): """ @@ -1944,22 +1992,26 @@ def get_have_global_pool(self, global_pool_details): errors = [] # To collect all error messages for pool_details in global_pool_ippool: - name = pool_details.get("name") - if name is None: - errors.append("Missing required parameter 'name' in global_pool_details: {}".format(pool_details)) - continue + delete_all = pool_details.get("delete_all") + if delete_all: + name = "" + else: + name = pool_details.get("name") + if name is None: + errors.append("Missing required parameter 'name' in global_pool_details: {}".format(pool_details)) + continue - name_length = len(name) - if name_length > 100: - errors.append("The length of the 'name' in global_pool_details should be less or equal to 100. Invalid_config: {}".format(pool_details)) + name_length = len(name) + if name_length > 100: + errors.append("The length of the 'name' in global_pool_details should be less or equal to 100. Invalid_config: {}".format(pool_details)) - if " " in name: - errors.append("The 'name' in global_pool_details should not contain any spaces. Invalid_config: {}".format(pool_details)) + if " " in name: + errors.append("The 'name' in global_pool_details should not contain any spaces. Invalid_config: {}".format(pool_details)) - pattern = r'^[\w\-./]+$' - if not re.match(pattern, name): - errors.append("The 'name' in global_pool_details should contain only letters, numbers, and -_./ characters. Invalid_config: {}" - .format(pool_details)) + pattern = r'^[\w\-./]+$' + if not re.match(pattern, name): + errors.append("The 'name' in global_pool_details should contain only letters, numbers, and -_./ characters. Invalid_config: {}" + .format(pool_details)) if errors: # If there are errors, return a failure status with all messages @@ -1967,19 +2019,28 @@ def get_have_global_pool(self, global_pool_details): self.status = "failed" return self + if name == "": + global_pool.append(self.global_pool_exists(name)) + self.log("Global pool details: {0}".format(global_pool), "DEBUG") + self.have.update({"globalPool": global_pool}) + self.msg = "Collecting the global all pool details from the Cisco Catalyst Center" + self.status = "success" + return self + for pool_details in global_pool_ippool: - name = pool_details.get("name") # If the Global Pool doesn't exist and a previous name is provided # Else try using the previous name global_pool.append(self.global_pool_exists(name)) - self.log("Global pool details of '{0}': {1}".format(name, global_pool[global_pool_index]), "DEBUG") + self.log("Global pool details of '{0}': {1}".format( + name, global_pool[global_pool_index]), "DEBUG") prev_name = pool_details.get("prev_name") if global_pool[global_pool_index].get("exists") is False and \ prev_name is not None: global_pool.pop() global_pool.append(self.global_pool_exists(prev_name)) if global_pool[global_pool_index].get("exists") is False: - self.msg = "Prev name {0} doesn't exist in global_pool_details".format(prev_name) + self.msg = "Prev name {0} doesn't exist in global_pool_details".format( + prev_name) self.status = "failed" return self @@ -2004,32 +2065,36 @@ def get_have_reserve_pool(self, reserve_pool_details): Returns: self - The current object with updated information. """ - reserve_pool = [] reserve_pool_index = 0 for item in reserve_pool_details: + delete_all = item.get("delete_all") name = item.get("name") - if name is None: - self.msg = "Missing required parameter 'name' in reserve_pool_details." - self.status = "failed" - return self + site_name = item.get("site_name") + if delete_all: + name = "" + else: + if name is None: + self.msg = "Missing required parameter 'name' in reserve_pool_details." + self.status = "failed" + return self - name_length = len(name) - if name_length > 100: - self.msg = "The length of the 'name' in reserve_pool_details should be less or equal to 100." - self.status = "failed" - return self + name_length = len(name) + if name_length > 100: + self.msg = "The length of the 'name' in reserve_pool_details should be less or equal to 100." + self.status = "failed" + return self - if " " in name: - self.msg = "The 'name' in reserve_pool_details should not contain any spaces." - self.status = "failed" - return self + if " " in name: + self.msg = "The 'name' in reserve_pool_details should not contain any spaces." + self.status = "failed" + return self - pattern = r'^[\w\-./]+$' - if not re.match(pattern, name): - self.msg = "The 'name' in reserve_pool_details should contain only letters, numbers and -_./ characters." - self.status = "failed" - return self + pattern = r'^[\w\-./]+$' + if not re.match(pattern, name): + self.msg = "The 'name' in reserve_pool_details should contain only letters, numbers and -_./ characters." + self.status = "failed" + return self site_name = item.get("site_name") self.log("Site Name: {0}".format(site_name), "DEBUG") @@ -2040,37 +2105,46 @@ def get_have_reserve_pool(self, reserve_pool_details): # Check if the Reserved Pool exists in Cisco Catalyst Center # based on the provided name and site name - reserve_pool.append(self.reserve_pool_exists(name, site_name)) - if not reserve_pool[reserve_pool_index].get("success"): + if self.reserve_pool_exists(name, site_name): + reserve_pool.append(self.reserve_pool_exists(name, site_name)) + else: + self.have.update({"reservePool": reserve_pool}) + return self + + if name != "" and not reserve_pool[reserve_pool_index].get("success"): + return self.check_return_status() + elif name == "" and len(reserve_pool[reserve_pool_index]) < 1: return self.check_return_status() - self.log("Reserved pool details for '{0}': {1}".format(name, reserve_pool[reserve_pool_index]), "DEBUG") - # If the Reserved Pool doesn't exist and a previous name is provided - # Else try using the previous name - prev_name = item.get("prev_name") - if reserve_pool[reserve_pool_index].get("exists") is False and \ - prev_name is not None: - reserve_pool.pop() - reserve_pool.append(self.reserve_pool_exists(prev_name, site_name)) - if not reserve_pool[reserve_pool_index].get("success"): - return self.check_return_status() - - # If the previous name doesn't exist in Cisco Catalyst Center, return with error - if reserve_pool[reserve_pool_index].get("exists") is False: - self.msg = "Prev name {0} doesn't exist in reserve_pool_details".format(prev_name) - self.status = "failed" - return self + self.log("Reserved pool details for {0}: {1}".format(name, reserve_pool[reserve_pool_index]), "DEBUG") + + if name != "": + # If the Reserved Pool doesn't exist and a previous name is provided + # Else try using the previous name + prev_name = item.get("prev_name") + if reserve_pool[reserve_pool_index].get("exists") is False and \ + prev_name is not None: + reserve_pool.pop() + reserve_pool.append(self.reserve_pool_exists(prev_name, site_name)) + if not reserve_pool[reserve_pool_index].get("success"): + return self.check_return_status() + + # If the previous name doesn't exist in Cisco Catalyst Center, return with error + if reserve_pool[reserve_pool_index].get("exists") is False: + self.msg = "Prev name {0} doesn't exist in reserve_pool_details".format(prev_name) + self.status = "failed" + return self - self.log("Reserved pool exists: {0}".format(reserve_pool[reserve_pool_index].get("exists")), "DEBUG") - self.log("Reserved pool: {0}".format(reserve_pool[reserve_pool_index].get("details")), "DEBUG") + self.log("Reserved pool exists: {0}".format(reserve_pool[reserve_pool_index].get("exists")), "DEBUG") + self.log("Reserved pool: {0}".format(reserve_pool[reserve_pool_index].get("details")), "DEBUG") - # If reserve pool exist, convert ipv6AddressSpace to the required format (boolean) - if reserve_pool[reserve_pool_index].get("exists"): - reserve_pool_info = reserve_pool[reserve_pool_index].get("details") - if reserve_pool_info.get("ipv6AddressSpace") == "False": - reserve_pool_info.update({"ipv6AddressSpace": False}) - else: - reserve_pool_info.update({"ipv6AddressSpace": True}) + # If reserve pool exist, convert ipv6AddressSpace to the required format (boolean) + if reserve_pool[reserve_pool_index].get("exists"): + reserve_pool_info = reserve_pool[reserve_pool_index].get("details") + if reserve_pool_info.get("ipv6AddressSpace") == "False": + reserve_pool_info.update({"ipv6AddressSpace": False}) + else: + reserve_pool_info.update({"ipv6AddressSpace": True}) reserve_pool_index += 1 @@ -3719,6 +3793,73 @@ def get_diff_merged(self, config): self.update_network(network_management).check_return_status() return self + def delete_single_pool(self, name, pool_id, function_name, pool_type): + """ + Delete single reserve/global pool from based on the pool ID and return + execution id and status message. + + Parameters: + name (str) - name contains ip pool name for release ip pool + pool_id (str) - ID contails IP pool id from get ip pool + function_name (str) - contains execution of sdk function name either + release_reserve_ip_subpool or delete_global_ip_pool + pool_type (str) - contains string message for log either Reserve or Global + + Returns: + execution_details (dict) - contains response for the delete execution + contains name, execution id and status message. + """ + self.log("{0} IP pool scheduled for deletion: {1}".format(pool_type, name), "INFO") + self.log("{0} pool '{1}' id: {2}".format(pool_type, name, pool_id), "DEBUG") + try: + response = self.dnac._exec( + family="network_settings", + function=function_name, + op_modifies=True, + params={"id": pool_id}, + ) + self.check_execution_response_status(response, + function_name).check_return_status() + self.log("Response received from delete {0} pool API: {1}". + format(pool_type, self.pprint(response)), "DEBUG") + executionid = response.get("executionId") + + success_msg, failed_msg = None, None + execution_details = {} + if pool_type == "Global": + success_msg = "Global pool deleted successfully" + failed_msg = "Unable to delete global pool reservation" + else: + success_msg = "Ip subpool reservation released successfully" + failed_msg = "Unable to release subpool reservation" + + if executionid: + execution_details = { + "name": name, + "execution_id": executionid, + "msg": success_msg + } + else: + self.msg = "No execution id received:'{name}'".format(name=name) + self.log(str(self.msg), "ERROR") + execution_details = { + "name": name, + "execution_id": None, + "msg": failed_msg + } + + return execution_details + + except Exception as msg: + self.msg = ( + "Exception occurred while deleting the {type} pool with the name '{name}': {msg}" + .format(name=name, msg=msg, type=pool_type) + ) + self.log(str(msg), "ERROR") + self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() + + return self + def delete_reserve_pool(self, reserve_pool_details): """ Delete a Reserve Pool by name in Cisco Catalyst Center @@ -3729,47 +3870,49 @@ def delete_reserve_pool(self, reserve_pool_details): Returns: self - The current object with Global Pool, Reserved Pool, Network Servers information. """ - reserve_pool_index = -1 for item in reserve_pool_details: reserve_pool_index += 1 - name = item.get("name") - reserve_pool_exists = self.have.get("reservePool")[reserve_pool_index].get("exists") + delete_all = item.get("delete_all") + site_name = item.get("site_name") result_reserve_pool = self.result.get("response")[1].get("reservePool") + if delete_all: + have_reserve_pool = reserve_pool_exists = self.have.get("reservePool")[reserve_pool_index] + result_reserve_pool.get("response").update({site_name: []}) + if have_reserve_pool and len(have_reserve_pool) > 0: + for each_pool in have_reserve_pool: + reserve_pool_exists = each_pool.get("exists") + + if not reserve_pool_exists: + result_reserve_pool.get("msg").update({name: "Reserve Pool not found"}) + self.log("Reserved Ip Subpool '{0}' not found".format(name), "INFO") + continue + else: + pool_name = each_pool.get("details", {}).get("name") + pool_id = each_pool.get("id") + execution_details = self.delete_single_pool(pool_name, pool_id, + "release_reserve_ip_subpool", + "Reserve") + result_reserve_pool["response"][site_name].append(execution_details) + else: + name = item.get("name") - if not reserve_pool_exists: - result_reserve_pool.get("msg").update({name: "Reserve Pool not found"}) - self.log("Reserved Ip Subpool '{0}' not found".format(name), "INFO") - continue + reserve_pool_exists = None + if self.have.get("reservePool"): + reserve_pool_exists = self.have.get("reservePool")[reserve_pool_index].get("exists") - self.log("Reserved IP pool scheduled for deletion: {0}" - .format(self.have.get("reservePool")[reserve_pool_index].get("name")), "INFO") - _id = self.have.get("reservePool")[reserve_pool_index].get("id") - self.log("Reserved pool '{0}' id: {1}".format(name, _id), "DEBUG") - try: - response = self.dnac._exec( - family="network_settings", - function="release_reserve_ip_subpool", - op_modifies=True, - params={"id": _id}, - ) - except Exception as msg: - self.msg = ( - "Exception occurred while updating the reserved pool with the name '{name}': {msg}" - .format(name=name, msg=msg) - ) - self.log(str(msg), "ERROR") - self.status = "failed" - return self + if not reserve_pool_exists: + result_reserve_pool.get("msg").update({name: "Reserve Pool not found"}) + self.log("Reserved Ip Subpool '{0}' not found".format(name), "INFO") + continue - self.check_execution_response_status(response, "release_reserve_ip_subpool").check_return_status() - executionid = response.get("executionId") - result_reserve_pool = self.result.get("response")[1].get("reservePool") - result_reserve_pool.get("response").update({name: {}}) - result_reserve_pool.get("response").get(name) \ - .update({"Execution Id": executionid}) - result_reserve_pool.get("msg") \ - .update({name: "Ip subpool reservation released successfully"}) + self.log("Reserved IP pool scheduled for deletion: {0}" + .format(self.have.get("reservePool")[reserve_pool_index].get("name")), "INFO") + _id = self.have.get("reservePool")[reserve_pool_index].get("id") + self.log("Reserved pool '{0}' id: {1}".format(name, _id), "DEBUG") + execution_details = self.delete_single_pool(name, _id, "release_reserve_ip_subpool", + "Reserve") + result_reserve_pool.get("response").update({name: execution_details}) self.msg = "Reserved pool(s) released successfully" self.status = "success" @@ -3789,40 +3932,36 @@ def delete_global_pool(self, global_pool_details): result_global_pool = self.result.get("response")[0].get("globalPool") global_pool_index = 0 for item in self.have.get("globalPool"): - global_pool_exists = item.get("exists") - name = global_pool_details.get("settings").get("ip_pool")[global_pool_index].get("name") - global_pool_index += 1 - if not global_pool_exists: - result_global_pool.get("msg").update({name: "Global Pool not found"}) - self.log("Global pool '{0}' not found".format(name), "INFO") - continue - - id = item.get("id") - try: - response = self.dnac._exec( - family="network_settings", - function="delete_global_ip_pool", - op_modifies=True, - params={"id": id}, - ) - except Exception as msg: - self.msg = ( - "Exception occurred while deleting the global pool with '{name}': {msg}" - .format(name=name, msg=msg) - ) - self.log(str(msg), "ERROR") - self.status = "failed" - return self - - # Check the execution status - self.check_execution_response_status(response, "delete_global_ip_pool").check_return_status() - executionid = response.get("executionId") + if isinstance(item, list): + for each_item in item: + global_pool_exists = each_item.get("exists") + pool_name = each_item.get("details").get("ipPoolName") + global_pool_index += 1 + + if not global_pool_exists: + result_global_pool.get("msg").update({name: "Global Pool not found"}) + self.log("Global pool '{0}' not found".format(name), "INFO") + continue + + execution_details = {} + pool_id = each_item.get("id") + execution_details = self.delete_single_pool(pool_name, pool_id, + "delete_global_ip_pool", + "Global") + result_global_pool["response"][pool_name].append(execution_details) + else: + global_pool_exists = item.get("exists") + name = global_pool_details.get("settings").get("ip_pool")[global_pool_index].get("name") + global_pool_index += 1 + if not global_pool_exists: + result_global_pool.get("msg").update({name: "Global Pool not found"}) + self.log("Global pool '{0}' not found".format(name), "INFO") + continue - # Update result information - result_global_pool = self.result.get("response")[0].get("globalPool") - result_global_pool.get("response").update({name: {}}) - result_global_pool.get("response").get(name).update({"Execution Id": executionid}) - result_global_pool.get("msg").update({name: "Global pool deleted successfully"}) + id = item.get("id") + execution_details = self.delete_single_pool(name, id, "delete_global_ip_pool", + "Global") + result_global_pool.get("response").update({name: execution_details}) self.msg = "Global pools deleted successfully" self.status = "success" @@ -3949,37 +4088,97 @@ def verify_diff_deleted(self, config): self.get_have(config) self.log("Current State (have): {0}".format(self.have), "INFO") self.log("Desired State (want): {0}".format(self.want), "INFO") + delete_all = [] if config.get("global_pool_details") is not None: global_pool_index = 0 global_pool_details = self.have.get("globalPool") for item in global_pool_details: - global_pool_exists = item.get("exists") - name = config.get("global_pool_details").get("settings") \ - .get("ip_pool")[global_pool_index].get("name") - if global_pool_exists: - self.msg = "Global Pool Config '{0}' is not applied to the Cisco Catalyst Center" \ - .format(name) - self.status = "failed" - return self + if isinstance(item, dict): + global_pool_exists = item.get("exists") + name = config.get("global_pool_details").get("settings") \ + .get("ip_pool")[global_pool_index].get("name") + if global_pool_exists: + self.msg = "Global Pool Config '{0}' is not applied to the Cisco Catalyst Center"\ + .format(name) + self.status = "failed" + return self - self.log("Successfully validated absence of Global Pool '{0}'.".format(name), "INFO") + self.log("Successfully validated absence of Global Pool '{0}'.". + format(name), "INFO") + else: + if len(item) > 0: + for each_ip_pool in item: + each_pool_validation = {} + global_pool_exists = each_ip_pool.get("exists") + name = each_ip_pool.get("details", {}).get("ipPoolName") + if global_pool_exists: + each_pool_validation = { + "name": name, + "msg": "Global Pool Config is not applied to the Catalyst Center", + "validation": "failed", + } + delete_all.append(each_pool_validation) global_pool_index += 1 + + if len(delete_all) > 0: + self.msg = "Global Pool Config is not applied to the Catalyst Center" + self.set_operation_result("failed", False, self.msg, + "ERROR", delete_all).check_return_status() + self.result.get("response")[0].get("globalPool").update({"Validation": "Success"}) + self.msg = "Successfully validated the absence of Global Pool." + self.log(self.msg, "INFO") + self.log("Last Check {0}".format(self.result.get("response")[0].get("globalPool")), "INFO") + del_response = self.result.get("response")[0].get("globalPool").get("response") + delete_all.append(del_response) + self.set_operation_result("success", True, self.msg, + "INFO", del_response).check_return_status() + if config.get("reserve_pool_details") is not None: reserve_pool_index = 0 reserve_pool_details = self.have.get("reservePool") + for item in reserve_pool_details: - reserve_pool_exists = item.get("exists") - name = config.get("reserve_pool_details")[reserve_pool_index].get("name") - if reserve_pool_exists: - self.msg = "Reserved Pool Config '{0}' is not applied to the Catalyst Center" \ - .format(name) - self.status = "failed" - return self + site_name = config.get("reserve_pool_details")[reserve_pool_index].get("site_name") + if isinstance(item, dict): + reserve_pool_exists = item.get("exists") + name = config.get("reserve_pool_details")[reserve_pool_index].get("name") + if reserve_pool_exists: + self.msg = "Reserved Pool Config '{0}' is not applied to the Catalyst Center" \ + .format(name) + self.status = "failed" + return self - self.log("Successfully validated the absence of Reserve Pool '{0}'.".format(name), "INFO") - self.result.get("response")[1].get("reservePool").update({"Validation": "Success"}) + self.log("Successfully validated the absence of Reserve Pool '{0}'.".format(name), "INFO") + reserve_pool_index += 1 + self.result.get("response")[1].get("reservePool").update({"Validation": "Success"}) + else: + if len(item) > 0: + for each_ip_pool in item: + each_pool_validation = {} + reserve_pool_exists = each_ip_pool.get("exists") + if reserve_pool_exists: + each_pool_validation = { + "site_name": site_name, + "name": each_ip_pool.get("details", {}).get("name"), + "msg": "Reserved Pool Config is not applied to the Catalyst Center", + "validation": "failed", + } + delete_all.append(each_pool_validation) + reserve_pool_index += 1 + + if len(delete_all) > 0: + self.msg = "Reserved Pool Config is not applied to the Catalyst Center" + self.set_operation_result("failed", False, self.msg, + "ERROR", delete_all).check_return_status() + + self.msg = "Successfully validated the absence of Reserve Pool." + self.log(self.msg, "INFO") + del_response = self.result.get("response")[1].get("reservePool").get("response") + delete_all.append(del_response) + self.set_operation_result("success", True, self.msg, + "INFO", del_response).check_return_status() self.msg = "Successfully validated the absence of Global Pool/Reserve Pool" self.status = "success" From 6a2473f7b9539b7b29b2200929d755115db8a1d3 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Wed, 11 Dec 2024 01:52:34 +0530 Subject: [PATCH 02/11] Network setting delete all enhancement --- .../network_settings_workflow_manager.py | 98 +++++++++++-------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index 388904874..01f0292c5 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -14,38 +14,39 @@ module: network_settings_workflow_manager short_description: Resource module for IP Address pools and network functions description: -- Manage operations on Global Pool, Reserve Pool, Network resources. -- API to create/update/delete global pool. -- API to reserve/update/delete an ip subpool from the global pool. -- API to update network settings for DHCP, Syslog, SNMP, NTP, Network AAA, Client and Endpoint AAA, + - Manage operations on Global Pool, Reserve Pool, Network resources. + - API to create/update/delete global pool. + - API to reserve/update/delete an ip subpool from the global pool. + - API to update network settings for DHCP, Syslog, SNMP, NTP, Network AAA, Client and Endpoint AAA, and/or DNS center server settings. version_added: '6.6.0' extends_documentation_fragment: - - cisco.dnac.workflow_manager_params +- cisco.dnac.workflow_manager_params author: Muthu Rakesh (@MUTHU-RAKESH-27) Madhan Sankaranarayanan (@madhansansel) Megha Kandari (@kandarimegha) options: - config_verify: - description: Set to True to verify the Cisco Catalyst Center after applying the playbook config. - type: bool - default: False - state: - description: The state of Cisco Catalyst Center after module completion. - type: str - choices: [merged, deleted] - default: merged - config: + config_verify: + description: Set to True to verify the Cisco Catalyst Center after applying the playbook config. + type: bool + default: False + state: + description: The state of Cisco Catalyst Center after module completion. + type: str + choices: [merged, deleted] + default: merged + config: + description: description: - List of details of global pool, reserved pool, network being managed. - type: list - elements: dict - required: true - suboptions: - global_pool_details: - description: Manages IPv4 and IPv6 IP pools in the global level. - type: dict - suboptions: + type: list + elements: dict + required: true + suboptions: + global_pool_details: + description: Manages IPv4 and IPv6 IP pools in the global level. + type: dict + suboptions: settings: description: Global Pool's settings. type: dict @@ -57,10 +58,10 @@ suboptions: name: description: - - Specifies the name assigned to the Global IP Pool. - - Required for the operations in the Global IP Pool. - - Length should be less than or equal to 100. - - Only letters, numbers and -_./ characters are allowed. + - Specifies the name assigned to the Global IP Pool. + - Required for the operations in the Global IP Pool. + - Length should be less than or equal to 100. + - Only letters, numbers and -_./ characters are allowed. type: str pool_type: description: > @@ -99,8 +100,14 @@ The former identifier for the global pool. It should be used exclusively when you need to update the global pool's name. type: str + delete_all: + description: > + Delete all IP pool from the global level of the global pool. + the default value is true + type: bool + required: false - reserve_pool_details: + reserve_pool_details: description: Reserved IP subpool details from the global pool. type: dict suboptions: @@ -111,10 +118,10 @@ type: str name: description: - - Name of the reserve IP subpool. - - Required for the operations in the Reserve IP Pool. - - Length should be less than or equal to 100. - - Only letters, numbers and -_./ characters are allowed. + - Name of the reserve IP subpool. + - Required for the operations in the Reserve IP Pool. + - Length should be less than or equal to 100. + - Only letters, numbers and -_./ characters are allowed. type: str pool_type: description: Type of the reserve ip sub pool. @@ -139,13 +146,13 @@ type: bool ipv4_global_pool: description: - - IP v4 Global pool address with cidr, example 175.175.0.0/16. - - If both 'ipv6_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. + - IP v4 Global pool address with cidr, example 175.175.0.0/16. + - If both 'ipv6_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. type: str ipv4_global_pool_name: description: - - Specifies the name to be associated with the IPv4 Global IP Pool. - - If both 'ipv4_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. + - Specifies the name to be associated with the IPv4 Global IP Pool. + - If both 'ipv4_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. type: str version_added: 6.14.0 ipv4_subnet: @@ -191,14 +198,14 @@ type: str ipv6_global_pool: description: - - The ipv6_global_pool is a required when the ipv6_address_space is set to true. - - It specifies the global IPv6 address pool using CIDR notation, such as "2001:db8:85a3::/64". - - In cases where both ipv6_global_pool and ipv6_global_pool_name are specified, ipv6_global_pool will take precedence. + - The ipv6_global_pool is a required when the ipv6_address_space is set to true. + - It specifies the global IPv6 address pool using CIDR notation, such as "2001:db8:85a3::/64". + - In cases where both ipv6_global_pool and ipv6_global_pool_name are specified, ipv6_global_pool will take precedence. type: str ipv6_global_pool_name: description: - - Specifies the name assigned to the Ip v6 Global IP Pool. - - If both 'ipv6_global_pool' and 'ipv6_global_pool_name' are provided, the 'ipv6_global_pool' will be given priority. + - Specifies the name assigned to the Ip v6 Global IP Pool. + - If both 'ipv6_global_pool' and 'ipv6_global_pool_name' are provided, the 'ipv6_global_pool' will be given priority. type: str version_added: 6.14.0 ipv6_subnet: @@ -226,7 +233,13 @@ Allows devices on IPv6 networks to self-configure their IP addresses autonomously, eliminating the need for manual setup. type: bool - network_management_details: + delete_all: + description: > + Delete all IP pool from the specific Site location of the reserve pool. + the default value is true + type: bool + required: false + network_management_details: description: Set default network settings for the site type: list elements: dict @@ -2065,6 +2078,7 @@ def get_have_reserve_pool(self, reserve_pool_details): Returns: self - The current object with updated information. """ + reserve_pool = [] reserve_pool_index = 0 for item in reserve_pool_details: From 9ee6fd6764cc796d06083d05a9b287cf3d0721c5 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Wed, 11 Dec 2024 01:57:00 +0530 Subject: [PATCH 03/11] Network setting delete all enhancement --- .../network_settings_workflow_manager.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index 01f0292c5..a53b2eadf 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -3,6 +3,7 @@ # Copyright (c) 2024, Cisco Systems # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + """Ansible module to perform operations on global pool, reserve pool and network in Cisco Catalyst Center.""" from __future__ import absolute_import, division, print_function @@ -14,14 +15,14 @@ module: network_settings_workflow_manager short_description: Resource module for IP Address pools and network functions description: - - Manage operations on Global Pool, Reserve Pool, Network resources. - - API to create/update/delete global pool. - - API to reserve/update/delete an ip subpool from the global pool. - - API to update network settings for DHCP, Syslog, SNMP, NTP, Network AAA, Client and Endpoint AAA, + - Manage operations on Global Pool, Reserve Pool, Network resources. + - API to create/update/delete global pool. + - API to reserve/update/delete an ip subpool from the global pool. + - API to update network settings for DHCP, Syslog, SNMP, NTP, Network AAA, Client and Endpoint AAA, and/or DNS center server settings. version_added: '6.6.0' extends_documentation_fragment: -- cisco.dnac.workflow_manager_params + - cisco.dnac.workflow_manager_params author: Muthu Rakesh (@MUTHU-RAKESH-27) Madhan Sankaranarayanan (@madhansansel) Megha Kandari (@kandarimegha) @@ -37,7 +38,6 @@ default: merged config: description: - description: - List of details of global pool, reserved pool, network being managed. type: list elements: dict @@ -58,10 +58,10 @@ suboptions: name: description: - - Specifies the name assigned to the Global IP Pool. - - Required for the operations in the Global IP Pool. - - Length should be less than or equal to 100. - - Only letters, numbers and -_./ characters are allowed. + - Specifies the name assigned to the Global IP Pool. + - Required for the operations in the Global IP Pool. + - Length should be less than or equal to 100. + - Only letters, numbers and -_./ characters are allowed. type: str pool_type: description: > @@ -118,10 +118,10 @@ type: str name: description: - - Name of the reserve IP subpool. - - Required for the operations in the Reserve IP Pool. - - Length should be less than or equal to 100. - - Only letters, numbers and -_./ characters are allowed. + - Name of the reserve IP subpool. + - Required for the operations in the Reserve IP Pool. + - Length should be less than or equal to 100. + - Only letters, numbers and -_./ characters are allowed. type: str pool_type: description: Type of the reserve ip sub pool. @@ -146,13 +146,13 @@ type: bool ipv4_global_pool: description: - - IP v4 Global pool address with cidr, example 175.175.0.0/16. - - If both 'ipv6_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. + - IP v4 Global pool address with cidr, example 175.175.0.0/16. + - If both 'ipv6_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. type: str ipv4_global_pool_name: description: - - Specifies the name to be associated with the IPv4 Global IP Pool. - - If both 'ipv4_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. + - Specifies the name to be associated with the IPv4 Global IP Pool. + - If both 'ipv4_global_pool' and 'ipv4_global_pool_name' are provided, the 'ipv4_global_pool' will be given priority. type: str version_added: 6.14.0 ipv4_subnet: @@ -198,14 +198,14 @@ type: str ipv6_global_pool: description: - - The ipv6_global_pool is a required when the ipv6_address_space is set to true. - - It specifies the global IPv6 address pool using CIDR notation, such as "2001:db8:85a3::/64". - - In cases where both ipv6_global_pool and ipv6_global_pool_name are specified, ipv6_global_pool will take precedence. + - The ipv6_global_pool is a required when the ipv6_address_space is set to true. + - It specifies the global IPv6 address pool using CIDR notation, such as "2001:db8:85a3::/64". + - In cases where both ipv6_global_pool and ipv6_global_pool_name are specified, ipv6_global_pool will take precedence. type: str ipv6_global_pool_name: description: - - Specifies the name assigned to the Ip v6 Global IP Pool. - - If both 'ipv6_global_pool' and 'ipv6_global_pool_name' are provided, the 'ipv6_global_pool' will be given priority. + - Specifies the name assigned to the Ip v6 Global IP Pool. + - If both 'ipv6_global_pool' and 'ipv6_global_pool_name' are provided, the 'ipv6_global_pool' will be given priority. type: str version_added: 6.14.0 ipv6_subnet: From dbd54bed7bd99879411505e8f6717037c1e24aa9 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Wed, 11 Dec 2024 02:10:13 +0530 Subject: [PATCH 04/11] Network setting delete all enhancement sanity --- .../network_settings_workflow_manager.py | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index a53b2eadf..9bb7a88ab 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -2024,7 +2024,7 @@ def get_have_global_pool(self, global_pool_details): pattern = r'^[\w\-./]+$' if not re.match(pattern, name): errors.append("The 'name' in global_pool_details should contain only letters, numbers, and -_./ characters. Invalid_config: {}" - .format(pool_details)) + .format(pool_details)) if errors: # If there are errors, return a failure status with all messages @@ -2122,8 +2122,8 @@ def get_have_reserve_pool(self, reserve_pool_details): if self.reserve_pool_exists(name, site_name): reserve_pool.append(self.reserve_pool_exists(name, site_name)) else: - self.have.update({"reservePool": reserve_pool}) - return self + self.have.update({"reservePool": reserve_pool}) + return self if name != "" and not reserve_pool[reserve_pool_index].get("success"): return self.check_return_status() @@ -3809,7 +3809,7 @@ def get_diff_merged(self, config): def delete_single_pool(self, name, pool_id, function_name, pool_type): """ - Delete single reserve/global pool from based on the pool ID and return + Delete single reserve/global pool from based on the pool ID and return execution id and status message. Parameters: @@ -3852,7 +3852,7 @@ def delete_single_pool(self, name, pool_id, function_name, pool_type): "name": name, "execution_id": executionid, "msg": success_msg - } + } else: self.msg = "No execution id received:'{name}'".format(name=name) self.log(str(self.msg), "ERROR") @@ -3860,7 +3860,7 @@ def delete_single_pool(self, name, pool_id, function_name, pool_type): "name": name, "execution_id": None, "msg": failed_msg - } + } return execution_details @@ -3905,8 +3905,8 @@ def delete_reserve_pool(self, reserve_pool_details): pool_name = each_pool.get("details", {}).get("name") pool_id = each_pool.get("id") execution_details = self.delete_single_pool(pool_name, pool_id, - "release_reserve_ip_subpool", - "Reserve") + "release_reserve_ip_subpool", + "Reserve") result_reserve_pool["response"][site_name].append(execution_details) else: name = item.get("name") @@ -3921,11 +3921,12 @@ def delete_reserve_pool(self, reserve_pool_details): continue self.log("Reserved IP pool scheduled for deletion: {0}" - .format(self.have.get("reservePool")[reserve_pool_index].get("name")), "INFO") + .format(self.have.get("reservePool")[reserve_pool_index].get("name")), "INFO") _id = self.have.get("reservePool")[reserve_pool_index].get("id") self.log("Reserved pool '{0}' id: {1}".format(name, _id), "DEBUG") - execution_details = self.delete_single_pool(name, _id, "release_reserve_ip_subpool", - "Reserve") + execution_details = self.delete_single_pool(name, _id, + "release_reserve_ip_subpool", + "Reserve") result_reserve_pool.get("response").update({name: execution_details}) self.msg = "Reserved pool(s) released successfully" @@ -3960,8 +3961,8 @@ def delete_global_pool(self, global_pool_details): execution_details = {} pool_id = each_item.get("id") execution_details = self.delete_single_pool(pool_name, pool_id, - "delete_global_ip_pool", - "Global") + "delete_global_ip_pool", + "Global") result_global_pool["response"][pool_name].append(execution_details) else: global_pool_exists = item.get("exists") @@ -3973,8 +3974,9 @@ def delete_global_pool(self, global_pool_details): continue id = item.get("id") - execution_details = self.delete_single_pool(name, id, "delete_global_ip_pool", - "Global") + execution_details = self.delete_single_pool(name, id, + "delete_global_ip_pool", + "Global") result_global_pool.get("response").update({name: execution_details}) self.msg = "Global pools deleted successfully" @@ -4109,11 +4111,10 @@ def verify_diff_deleted(self, config): for item in global_pool_details: if isinstance(item, dict): global_pool_exists = item.get("exists") - name = config.get("global_pool_details").get("settings") \ - .get("ip_pool")[global_pool_index].get("name") + name = config.get("global_pool_details").get("settings")\ + .get("ip_pool")[global_pool_index].get("name") if global_pool_exists: - self.msg = "Global Pool Config '{0}' is not applied to the Cisco Catalyst Center"\ - .format(name) + self.msg = "Global Pool Config '{0}' is not applied to the Cisco Catalyst Center".format(name) self.status = "failed" return self @@ -4137,7 +4138,7 @@ def verify_diff_deleted(self, config): if len(delete_all) > 0: self.msg = "Global Pool Config is not applied to the Catalyst Center" self.set_operation_result("failed", False, self.msg, - "ERROR", delete_all).check_return_status() + "ERROR", delete_all).check_return_status() self.result.get("response")[0].get("globalPool").update({"Validation": "Success"}) @@ -4147,7 +4148,7 @@ def verify_diff_deleted(self, config): del_response = self.result.get("response")[0].get("globalPool").get("response") delete_all.append(del_response) self.set_operation_result("success", True, self.msg, - "INFO", del_response).check_return_status() + "INFO", del_response).check_return_status() if config.get("reserve_pool_details") is not None: reserve_pool_index = 0 @@ -4159,8 +4160,8 @@ def verify_diff_deleted(self, config): reserve_pool_exists = item.get("exists") name = config.get("reserve_pool_details")[reserve_pool_index].get("name") if reserve_pool_exists: - self.msg = "Reserved Pool Config '{0}' is not applied to the Catalyst Center" \ - .format(name) + self.msg = "Reserved Pool Config '{0}' is not applied to the Catalyst Center"\ + .format(name) self.status = "failed" return self @@ -4185,14 +4186,14 @@ def verify_diff_deleted(self, config): if len(delete_all) > 0: self.msg = "Reserved Pool Config is not applied to the Catalyst Center" self.set_operation_result("failed", False, self.msg, - "ERROR", delete_all).check_return_status() + "ERROR", delete_all).check_return_status() self.msg = "Successfully validated the absence of Reserve Pool." self.log(self.msg, "INFO") del_response = self.result.get("response")[1].get("reservePool").get("response") delete_all.append(del_response) self.set_operation_result("success", True, self.msg, - "INFO", del_response).check_return_status() + "INFO", del_response).check_return_status() self.msg = "Successfully validated the absence of Global Pool/Reserve Pool" self.status = "success" From 701579034983dafff22db87b91e61677d9f4f839 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Thu, 12 Dec 2024 19:39:33 +0530 Subject: [PATCH 05/11] Breaking existing create global fixed --- .../network_settings_workflow_manager.py | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index 9bb7a88ab..2e1cbf9b6 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -1885,10 +1885,10 @@ def global_pool_exists(self, name): global_pool.update({"exists": True}) global_pool.update({"id": global_pool_details.get("id")}) global_pool["details"] = self.get_global_pool_params(global_pool_details) - self.log("Formatted global pool details: {0}".format(global_pool), "DEBUG") - return global_pool + break - if global_pool_details and isinstance(global_pool_details, list): + if global_pool_details and isinstance(global_pool_details, list)\ + and name == "": self.log("Global pool found {0}".format( self.pprint(global_pool_details)), "INFO") @@ -1899,7 +1899,14 @@ def global_pool_exists(self, name): "details": self.get_global_pool_params(each_pool) } all_global_pool.append(global_del_pool) - value += 25 + + if len(all_global_pool_details) == 25: + value += 25 + else: + break + + self.log("Formatted global pool details: {0}".format(global_pool), "DEBUG") + return global_pool def reserve_pool_exists(self, name, site_name): """ @@ -2006,10 +2013,10 @@ def get_have_global_pool(self, global_pool_details): for pool_details in global_pool_ippool: delete_all = pool_details.get("delete_all") + name = pool_details.get("name") if delete_all: name = "" else: - name = pool_details.get("name") if name is None: errors.append("Missing required parameter 'name' in global_pool_details: {}".format(pool_details)) continue @@ -2043,6 +2050,10 @@ def get_have_global_pool(self, global_pool_details): for pool_details in global_pool_ippool: # If the Global Pool doesn't exist and a previous name is provided # Else try using the previous name + name = pool_details.get("name") + if pool_details.get("delete_all"): + name = "" + global_pool.append(self.global_pool_exists(name)) self.log("Global pool details of '{0}': {1}".format( name, global_pool[global_pool_index]), "DEBUG") From d344c3c68f25bcddc5a62761e76bdebb744e4ddb Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Thu, 12 Dec 2024 19:53:57 +0530 Subject: [PATCH 06/11] Breaking existing create global fixed --- plugins/modules/network_settings_workflow_manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index 2e1cbf9b6..a23d0ed31 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -1887,8 +1887,7 @@ def global_pool_exists(self, name): global_pool["details"] = self.get_global_pool_params(global_pool_details) break - if global_pool_details and isinstance(global_pool_details, list)\ - and name == "": + if global_pool_details and isinstance(global_pool_details, list) and name == "": self.log("Global pool found {0}".format( self.pprint(global_pool_details)), "INFO") From bf8a4eadaef607f9e46e3910e406babe1ceeb879 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Fri, 13 Dec 2024 18:10:23 +0530 Subject: [PATCH 07/11] Negative reserve ip pool testing cleared --- .../modules/network_settings_workflow_manager.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index a23d0ed31..837fa189e 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -3904,6 +3904,13 @@ def delete_reserve_pool(self, reserve_pool_details): have_reserve_pool = reserve_pool_exists = self.have.get("reservePool")[reserve_pool_index] result_reserve_pool.get("response").update({site_name: []}) if have_reserve_pool and len(have_reserve_pool) > 0: + if isinstance(have_reserve_pool, dict): + reserve_pool_exists = have_reserve_pool.get("exists") + if not reserve_pool_exists: + result_reserve_pool.get("msg").update({site_name: "Reserve Pool not found"}) + self.log("Reserved Ip Subpool '{0}' not found".format(site_name), "INFO") + continue + for each_pool in have_reserve_pool: reserve_pool_exists = each_pool.get("exists") @@ -4172,12 +4179,14 @@ def verify_diff_deleted(self, config): if reserve_pool_exists: self.msg = "Reserved Pool Config '{0}' is not applied to the Catalyst Center"\ .format(name) - self.status = "failed" - return self + self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() self.log("Successfully validated the absence of Reserve Pool '{0}'.".format(name), "INFO") reserve_pool_index += 1 - self.result.get("response")[1].get("reservePool").update({"Validation": "Success"}) + + if self.result.get("response"): + self.result.get("response")[1].get("reservePool").update({"Validation": "Success"}) + else: if len(item) > 0: for each_ip_pool in item: From 38837e07e94bb698ed363d77b6947c067d0934b0 Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Tue, 17 Dec 2024 08:57:12 +0530 Subject: [PATCH 08/11] Address all code reveiw comments --- .../network_settings_workflow_manager.py | 169 ++++++++++-------- 1 file changed, 97 insertions(+), 72 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index 837fa189e..c7c61505d 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -100,10 +100,10 @@ The former identifier for the global pool. It should be used exclusively when you need to update the global pool's name. type: str - delete_all: + force_delete: description: > - Delete all IP pool from the global level of the global pool. - the default value is true + Forcefully delete all IP pools from the global level of the global pool. + The default value is false. type: bool required: false @@ -233,10 +233,10 @@ Allows devices on IPv6 networks to self-configure their IP addresses autonomously, eliminating the need for manual setup. type: bool - delete_all: + force_delete: description: > - Delete all IP pool from the specific Site location of the reserve pool. - the default value is true + Forcefully delete all IP pools from the global level of the global pool. + The default value is false. type: bool required: false network_management_details: @@ -763,7 +763,7 @@ def validate_input(self): "name": {"type": 'string'}, "prev_name": {"type": 'string'}, "pool_type": {"type": 'string', "choices": ["Generic", "Tunnel"]}, - 'delete_all': {'type': 'bool', 'required': False, 'default': True}, + 'force_delete': {'type': 'bool', 'required': False, 'default': True}, } } }, @@ -795,7 +795,7 @@ def validate_input(self): "type": 'string', "choices": ["Generic", "LAN", "Management", "Service", "WAN"] }, - 'delete_all': {'type': 'bool', 'required': False, 'default': True}, + 'force_delete': {'type': 'bool', 'required': False, 'default': True}, }, "network_management_details": { "type": 'list', @@ -1759,7 +1759,7 @@ def get_network_params_v2(self, site_name, site_id): return network_details - def get_reserved_ip_subpool(self, site_id): + def get_reserved_ip_subpool(self, site_name, site_id): """ Retrieve all the reserved IP subpool details from the Cisco Catalyst Center. @@ -1771,7 +1771,7 @@ def get_reserved_ip_subpool(self, site_id): self (object) - The current object with updated desired reserved subpool information. """ - value = 1 + offset = 1 self.all_reserved_pool_details.update({site_id: []}) start_time = time.time() while True: @@ -1782,14 +1782,12 @@ def get_reserved_ip_subpool(self, site_id): op_modifies=True, params={ "site_id": site_id, - "offset": value + "offset": offset } ) except Exception as msg: - self.msg = ( - "Exception occurred while getting the reserved pool details " - "from Cisco Catalyst Center: {msg}".format(msg=msg) - ) + self.msg = "Exception occurred while fetching reserved pool details for site '{0}': {1}".format( + site_name, site_id) self.log(str(msg), "ERROR") self.status = "failed" return self @@ -1801,17 +1799,19 @@ def get_reserved_ip_subpool(self, site_id): reserve_pool_details = response.get("response") if not reserve_pool_details: - self.log("No subpools are reserved in the site with ID - '{0}'." - .format(site_id), "DEBUG") + self.log("No subpools are reserved in the site with ID - '{0}': '{1}'." + .format(site_id, site_name), "DEBUG") return self self.all_reserved_pool_details.get(site_id).extend(reserve_pool_details) - if len(reserve_pool_details) == 25: - value += 25 - else: + if len(reserve_pool_details) < 25: + self.log("Found {0} record(s), No more record available for the next offset" + .format(str(len(reserve_pool_details))), "INFO") break + offset += 25 + end_time = time.time() if (end_time - start_time) >= self.max_timeout: self.msg = ( @@ -1843,13 +1843,13 @@ def global_pool_exists(self, name): "id": None } all_global_pool = [] - value = 1 + offset = 1 while True: try: response = self.dnac._exec( family="network_settings", function="get_global_pool", - params={"offset": value} + params={"offset": offset} ) except Exception as msg: self.msg = ( @@ -1899,11 +1899,11 @@ def global_pool_exists(self, name): } all_global_pool.append(global_del_pool) - if len(all_global_pool_details) == 25: - value += 25 - else: + if len(all_global_pool_details) < 25: break + offset += 25 + self.log("Formatted global pool details: {0}".format(global_pool), "DEBUG") return global_pool @@ -1938,7 +1938,7 @@ def reserve_pool_exists(self, name, site_name): return reserve_pool if not self.all_reserved_pool_details.get(site_id): - self.get_reserved_ip_subpool(site_id) + self.get_reserved_ip_subpool(site_name, site_id) if not self.all_reserved_pool_details.get(site_id): self.log("Reserved pool {0} does not exist in the site {1}" @@ -1963,7 +1963,7 @@ def reserve_pool_exists(self, name, site_name): return reserve_pool if reserve_pool_details and isinstance(reserve_pool_details, list): - self.log("Reserve pool found for the site '{0}': {1}" + self.log("Found reserve pools for site '{0}': {1}" .format(site_name, self.pprint(reserve_pool_details)), "INFO") all_reserve_pool = [] for each_pool in reserve_pool_details: @@ -2011,7 +2011,7 @@ def get_have_global_pool(self, global_pool_details): errors = [] # To collect all error messages for pool_details in global_pool_ippool: - delete_all = pool_details.get("delete_all") + delete_all = pool_details.get("force_delete") name = pool_details.get("name") if delete_all: name = "" @@ -2042,7 +2042,7 @@ def get_have_global_pool(self, global_pool_details): global_pool.append(self.global_pool_exists(name)) self.log("Global pool details: {0}".format(global_pool), "DEBUG") self.have.update({"globalPool": global_pool}) - self.msg = "Collecting the global all pool details from the Cisco Catalyst Center" + self.msg = "Collected all global pool details from the Cisco Catalyst Center." self.status = "success" return self @@ -2050,7 +2050,7 @@ def get_have_global_pool(self, global_pool_details): # If the Global Pool doesn't exist and a previous name is provided # Else try using the previous name name = pool_details.get("name") - if pool_details.get("delete_all"): + if pool_details.get("force_delete"): name = "" global_pool.append(self.global_pool_exists(name)) @@ -2092,7 +2092,7 @@ def get_have_reserve_pool(self, reserve_pool_details): reserve_pool = [] reserve_pool_index = 0 for item in reserve_pool_details: - delete_all = item.get("delete_all") + delete_all = item.get("force_delete") name = item.get("name") site_name = item.get("site_name") if delete_all: @@ -2140,14 +2140,17 @@ def get_have_reserve_pool(self, reserve_pool_details): elif name == "" and len(reserve_pool[reserve_pool_index]) < 1: return self.check_return_status() - self.log("Reserved pool details for {0}: {1}".format(name, reserve_pool[reserve_pool_index]), "DEBUG") + self.log("Reserved pool details for {0}: {1}" + .format(name, reserve_pool[reserve_pool_index]), "DEBUG") if name != "": # If the Reserved Pool doesn't exist and a previous name is provided # Else try using the previous name prev_name = item.get("prev_name") if reserve_pool[reserve_pool_index].get("exists") is False and \ - prev_name is not None: + prev_name is not None: + self.log("Current pool does not exist. Checking for previous name '{0}'." + .format(prev_name), "DEBUG") reserve_pool.pop() reserve_pool.append(self.reserve_pool_exists(prev_name, site_name)) if not reserve_pool[reserve_pool_index].get("success"): @@ -3817,7 +3820,7 @@ def get_diff_merged(self, config): self.update_network(network_management).check_return_status() return self - def delete_single_pool(self, name, pool_id, function_name, pool_type): + def delete_ip_pool(self, name, pool_id, function_name, pool_type): """ Delete single reserve/global pool from based on the pool ID and return execution id and status message. @@ -3897,54 +3900,65 @@ def delete_reserve_pool(self, reserve_pool_details): reserve_pool_index = -1 for item in reserve_pool_details: reserve_pool_index += 1 - delete_all = item.get("delete_all") + delete_all = item.get("force_delete") site_name = item.get("site_name") result_reserve_pool = self.result.get("response")[1].get("reservePool") if delete_all: - have_reserve_pool = reserve_pool_exists = self.have.get("reservePool")[reserve_pool_index] + self.log("Delete all reserved pools operation initiated for site '{0}'" + .format(site_name), "INFO") + have_reserve_pool = reserve_pool = self.have.get("reservePool")[reserve_pool_index] result_reserve_pool.get("response").update({site_name: []}) if have_reserve_pool and len(have_reserve_pool) > 0: if isinstance(have_reserve_pool, dict): - reserve_pool_exists = have_reserve_pool.get("exists") - if not reserve_pool_exists: + self.log("Found reserved pools for site '{0}': {1}" + .format(site_name, self.pprint(have_reserve_pool)), "DEBUG") + reserve_pool = have_reserve_pool.get("exists") + if not reserve_pool: result_reserve_pool.get("msg").update({site_name: "Reserve Pool not found"}) - self.log("Reserved Ip Subpool '{0}' not found".format(site_name), "INFO") + self.log("Reserved IP Subpool '{0}' not found".format(site_name), "INFO") continue for each_pool in have_reserve_pool: - reserve_pool_exists = each_pool.get("exists") - - if not reserve_pool_exists: - result_reserve_pool.get("msg").update({name: "Reserve Pool not found"}) - self.log("Reserved Ip Subpool '{0}' not found".format(name), "INFO") + if not each_pool.get("exists"): + result_reserve_pool["msg"].update({site_name: "Reserve Pool not found"}) + self.log("Reserved IP Subpool '{0}' not found for deletion".format(site_name), "INFO") continue - else: - pool_name = each_pool.get("details", {}).get("name") - pool_id = each_pool.get("id") - execution_details = self.delete_single_pool(pool_name, pool_id, - "release_reserve_ip_subpool", - "Reserve") - result_reserve_pool["response"][site_name].append(execution_details) + + pool_name = each_pool.get("details", {}).get("name") + pool_id = each_pool.get("id") + self.log("Processing deletion for reserved pool '{0}' with ID '{1}'" + .format(pool_name, pool_id), "INFO") + execution_details = self.delete_ip_pool(pool_name, pool_id, + "release_reserve_ip_subpool", + "Reserve") + result_reserve_pool["response"][site_name].append(execution_details) + self.log("Deletion completed for reserved pool '{0}' with ID '{1}'" + .format(pool_name, pool_id), "DEBUG") + else: + result_reserve_pool["msg"].update({site_name: "No Reserve Pools available"}) + self.log("No Reserved IP Subpools found for site '{0}'. Skipping deletion." + .format(site_name), "INFO") else: - name = item.get("name") + pool_name = item.get("name") + pool_id = self.have.get("reservePool")[reserve_pool_index].get("id") + self.log("Delete operation initiated for specific reserved pool '{0}'".format(pool_name), "INFO") - reserve_pool_exists = None + reserve_pool = None if self.have.get("reservePool"): - reserve_pool_exists = self.have.get("reservePool")[reserve_pool_index].get("exists") + reserve_pool = self.have.get("reservePool")[reserve_pool_index].get("exists") - if not reserve_pool_exists: - result_reserve_pool.get("msg").update({name: "Reserve Pool not found"}) - self.log("Reserved Ip Subpool '{0}' not found".format(name), "INFO") + if not reserve_pool: + result_reserve_pool.get("msg").update({pool_name: "Reserve Pool not found"}) + self.log("Reserved IP Subpool '{0}' not found. Skipping deletion.".format(pool_name), "INFO") continue - self.log("Reserved IP pool scheduled for deletion: {0}" - .format(self.have.get("reservePool")[reserve_pool_index].get("name")), "INFO") - _id = self.have.get("reservePool")[reserve_pool_index].get("id") - self.log("Reserved pool '{0}' id: {1}".format(name, _id), "DEBUG") - execution_details = self.delete_single_pool(name, _id, - "release_reserve_ip_subpool", - "Reserve") - result_reserve_pool.get("response").update({name: execution_details}) + self.log("Reserved IP pool '{0}' scheduled for deletion".format(pool_name), "INFO") + self.log("Reserved pool '{0}' ID: {1}".format(pool_name, pool_id), "DEBUG") + execution_details = self.delete_ip_pool( + pool_name, pool_id, "release_reserve_ip_subpool", "Reserve" + ) + self.log("Deletion completed for reserved pool '{0}' with ID '{1}'".format(pool_name, pool_id), "DEBUG") + result_reserve_pool["response"].update({pool_name: execution_details}) self.msg = "Reserved pool(s) released successfully" self.status = "success" @@ -3965,6 +3979,7 @@ def delete_global_pool(self, global_pool_details): global_pool_index = 0 for item in self.have.get("globalPool"): if isinstance(item, list): + self.log("Processing global pool deletion for a list of items", "INFO") for each_item in item: global_pool_exists = each_item.get("exists") pool_name = each_item.get("details").get("ipPoolName") @@ -3977,23 +3992,26 @@ def delete_global_pool(self, global_pool_details): execution_details = {} pool_id = each_item.get("id") - execution_details = self.delete_single_pool(pool_name, pool_id, - "delete_global_ip_pool", - "Global") + execution_details = self.delete_ip_pool(pool_name, pool_id, + "delete_global_ip_pool", + "Global") + self.log("Deletion completed for global pool '{0}'".format(pool_name), "DEBUG") result_global_pool["response"][pool_name].append(execution_details) else: + self.log("Processing global pool deletion for a single item", "INFO") global_pool_exists = item.get("exists") name = global_pool_details.get("settings").get("ip_pool")[global_pool_index].get("name") global_pool_index += 1 if not global_pool_exists: result_global_pool.get("msg").update({name: "Global Pool not found"}) - self.log("Global pool '{0}' not found".format(name), "INFO") + self.log("Global pool '{0}' not found. Skipping deletion.".format(pool_name), "INFO") continue + self.log("Global pool '{0}' exists. Proceeding with deletion.".format(pool_name), "INFO") id = item.get("id") - execution_details = self.delete_single_pool(name, id, - "delete_global_ip_pool", - "Global") + execution_details = self.delete_ip_pool(name, id, + "delete_global_ip_pool", + "Global") result_global_pool.get("response").update({name: execution_details}) self.msg = "Global pools deleted successfully" @@ -4123,6 +4141,7 @@ def verify_diff_deleted(self, config): self.log("Desired State (want): {0}".format(self.want), "INFO") delete_all = [] if config.get("global_pool_details") is not None: + self.log("Starting validation for Global Pool absence.", "INFO") global_pool_index = 0 global_pool_details = self.have.get("globalPool") for item in global_pool_details: @@ -4150,6 +4169,7 @@ def verify_diff_deleted(self, config): "validation": "failed", } delete_all.append(each_pool_validation) + global_pool_index += 1 if len(delete_all) > 0: @@ -4168,6 +4188,7 @@ def verify_diff_deleted(self, config): "INFO", del_response).check_return_status() if config.get("reserve_pool_details") is not None: + self.log("Starting validation for Reserve Pool absence.", "INFO") reserve_pool_index = 0 reserve_pool_details = self.have.get("reservePool") @@ -4176,6 +4197,7 @@ def verify_diff_deleted(self, config): if isinstance(item, dict): reserve_pool_exists = item.get("exists") name = config.get("reserve_pool_details")[reserve_pool_index].get("name") + if reserve_pool_exists: self.msg = "Reserved Pool Config '{0}' is not applied to the Catalyst Center"\ .format(name) @@ -4193,6 +4215,8 @@ def verify_diff_deleted(self, config): each_pool_validation = {} reserve_pool_exists = each_ip_pool.get("exists") if reserve_pool_exists: + self.log("Reserve Pool '{0}' found. Marking as failed validation." + .format(name), "ERROR") each_pool_validation = { "site_name": site_name, "name": each_ip_pool.get("details", {}).get("name"), @@ -4200,6 +4224,7 @@ def verify_diff_deleted(self, config): "validation": "failed", } delete_all.append(each_pool_validation) + reserve_pool_index += 1 if len(delete_all) > 0: From 50e67143573b05d383f5db155857b2161ad80b4d Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Tue, 17 Dec 2024 09:04:46 +0530 Subject: [PATCH 09/11] Address all code reveiw comments sanity fixed --- plugins/modules/network_settings_workflow_manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index c7c61505d..a37ea4a2d 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -2147,8 +2147,7 @@ def get_have_reserve_pool(self, reserve_pool_details): # If the Reserved Pool doesn't exist and a previous name is provided # Else try using the previous name prev_name = item.get("prev_name") - if reserve_pool[reserve_pool_index].get("exists") is False and \ - prev_name is not None: + if reserve_pool[reserve_pool_index].get("exists") is False and prev_name is not None: self.log("Current pool does not exist. Checking for previous name '{0}'." .format(prev_name), "DEBUG") reserve_pool.pop() From 347400ef6fb4c54b07c5776952cc4477d01945bc Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Tue, 17 Dec 2024 14:20:27 +0530 Subject: [PATCH 10/11] Pool name change updated --- plugins/modules/network_settings_workflow_manager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index a37ea4a2d..fbf123ef5 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -3985,8 +3985,8 @@ def delete_global_pool(self, global_pool_details): global_pool_index += 1 if not global_pool_exists: - result_global_pool.get("msg").update({name: "Global Pool not found"}) - self.log("Global pool '{0}' not found".format(name), "INFO") + result_global_pool.get("msg").update({pool_name: "Global Pool not found"}) + self.log("Global pool '{0}' not found".format(pool_name), "INFO") continue execution_details = {} @@ -3999,19 +3999,19 @@ def delete_global_pool(self, global_pool_details): else: self.log("Processing global pool deletion for a single item", "INFO") global_pool_exists = item.get("exists") - name = global_pool_details.get("settings").get("ip_pool")[global_pool_index].get("name") + pool_name = global_pool_details.get("settings").get("ip_pool")[global_pool_index].get("name") global_pool_index += 1 if not global_pool_exists: - result_global_pool.get("msg").update({name: "Global Pool not found"}) + result_global_pool.get("msg").update({pool_name: "Global Pool not found"}) self.log("Global pool '{0}' not found. Skipping deletion.".format(pool_name), "INFO") continue self.log("Global pool '{0}' exists. Proceeding with deletion.".format(pool_name), "INFO") id = item.get("id") - execution_details = self.delete_ip_pool(name, id, + execution_details = self.delete_ip_pool(pool_name, id, "delete_global_ip_pool", "Global") - result_global_pool.get("response").update({name: execution_details}) + result_global_pool.get("response").update({pool_name: execution_details}) self.msg = "Global pools deleted successfully" self.status = "success" From 4134280eaa04e7edfafa0b98cc2f54f877f447fc Mon Sep 17 00:00:00 2001 From: md-rafeek Date: Tue, 17 Dec 2024 22:26:15 +0530 Subject: [PATCH 11/11] Updated the code reveiw comments --- .../network_settings_workflow_manager.py | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/plugins/modules/network_settings_workflow_manager.py b/plugins/modules/network_settings_workflow_manager.py index fbf123ef5..db6be1003 100644 --- a/plugins/modules/network_settings_workflow_manager.py +++ b/plugins/modules/network_settings_workflow_manager.py @@ -106,6 +106,7 @@ The default value is false. type: bool required: false + default: false reserve_pool_details: description: Reserved IP subpool details from the global pool. @@ -235,10 +236,12 @@ type: bool force_delete: description: > - Forcefully delete all IP pools from the global level of the global pool. + Forcefully delete all IP pools from the reserve level of the IP sub-pool. The default value is false. type: bool required: false + default: false + network_management_details: description: Set default network settings for the site type: list @@ -1900,6 +1903,8 @@ def global_pool_exists(self, name): all_global_pool.append(global_del_pool) if len(all_global_pool_details) < 25: + self.log("Found {0} record(s), No more record available for the next offset" + .format(str(len(all_global_pool_details))), "INFO") break offset += 25 @@ -3848,10 +3853,9 @@ def delete_ip_pool(self, name, pool_id, function_name, pool_type): function_name).check_return_status() self.log("Response received from delete {0} pool API: {1}". format(pool_type, self.pprint(response)), "DEBUG") - executionid = response.get("executionId") - + execution_id = response.get("executionId") success_msg, failed_msg = None, None - execution_details = {} + if pool_type == "Global": success_msg = "Global pool deleted successfully" failed_msg = "Unable to delete global pool reservation" @@ -3859,32 +3863,33 @@ def delete_ip_pool(self, name, pool_id, function_name, pool_type): success_msg = "Ip subpool reservation released successfully" failed_msg = "Unable to release subpool reservation" - if executionid: - execution_details = { + if execution_id: + return { "name": name, - "execution_id": executionid, - "msg": success_msg + "execution_id": execution_id, + "msg": success_msg, + "status": "success" } - else: - self.msg = "No execution id received:'{name}'".format(name=name) - self.log(str(self.msg), "ERROR") - execution_details = { - "name": name, - "execution_id": None, - "msg": failed_msg - } - - return execution_details + self.log("No execution ID received for '{name}'".format(name=name), "ERROR") + return { + "name": name, + "execution_id": None, + "msg": failed_msg, + "status": "failed" + } - except Exception as msg: - self.msg = ( - "Exception occurred while deleting the {type} pool with the name '{name}': {msg}" - .format(name=name, msg=msg, type=pool_type) + except Exception as e: + error_msg = ( + "Exception occurred while deleting the {type} pool with the name '{name}': {error}" + .format(name=name, error=str(e), type=pool_type) ) - self.log(str(msg), "ERROR") - self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() - - return self + self.log(error_msg, "ERROR") + return { + "name": name, + "execution_id": None, + "msg": error_msg, + "status": "failed" + } def delete_reserve_pool(self, reserve_pool_details): """