diff --git a/plugins/modules/site_workflow_manager.py b/plugins/modules/site_workflow_manager.py index a01c25b930..ce91f700b3 100644 --- a/plugins/modules/site_workflow_manager.py +++ b/plugins/modules/site_workflow_manager.py @@ -502,8 +502,7 @@ def get_current_site(self, site): """ site_info = {} - location = get_dict_result(site[0].get( - "additionalInfo"), 'nameSpace', "Location") + location = get_dict_result(site[0].get("additionalInfo"), 'nameSpace', "Location") typeinfo = location.get("attributes").get("type") if typeinfo == "area": @@ -539,7 +538,7 @@ def get_current_site(self, site): name=site[0].get("name"), parentName=site[0].get("siteNameHierarchy").split( "/" + site[0].get("name"))[0], - rfmodel=rf_model, + rf_model=floor_plan.get(rf_model), width=map_geometry.get("attributes").get("width"), length=map_geometry.get("attributes").get("length"), height=map_geometry.get("attributes").get("height"), @@ -555,111 +554,147 @@ def get_current_site(self, site): self.log("Current site details: {0}".format(str(current_site)), "INFO") return current_site + def get_site_v1(self, site_name_hierarchy): + """ + Retrieve site details from Cisco Catalyst Center based on the provided site name. + Args: + - site_name_hierarchy (str): The name or hierarchy of the site to be retrieved. + Returns: + - response (dict or None): The response from the API call, typically a dictionary containing site details. + Returns None if an error occurs or if the response is empty. + Criteria: + - This function uses the Cisco Catalyst Center SDK to execute the 'get_sites' function from the 'site_design' family. + - If the response is empty, a warning is logged. + - Any exceptions during the API call are caught, logged as errors, and the function returns None. + """ + self.log("Fetching site details for site hierarchy: '{0}'".format(site_name_hierarchy), "INFO") + try: + response = self.dnac._exec( + family="sites", + function='get_site', + op_modifies=True, + params={"name": site_name_hierarchy}, + ) + + if not response: + self.log("Empty response received for site: {0}".format(site_name_hierarchy), "WARNING") + return None + + self.log("Received API response for site '{0}' from 'get_sites': {1}".format(site_name_hierarchy, response), "DEBUG") + return response + + except Exception as e: + self.log("An error occurred in 'get_sites':{0}".format(e), "ERROR") + return None + def site_exists(self): """ + Check if the site exists in Cisco Catalyst Center. Parameters: - - self (object): An instance of the class containing the method. + - self (object): An instance of the class containing the method. + Returns: - - tuple: A tuple containing a boolean indicating whether the site exists and - a dictionary containing information about the existing site. - The returned tuple includes two elements: - - site_exists (bool): Indicates whether the site exists. - - dict: Contains information about the existing site. If the - site doesn't exist, this dictionary is empty. + - tuple: A tuple containing a boolean indicating whether the site exists and + a dictionary containing information about the existing site. + The returned tuple includes two elements: + - site_exists (bool): Indicates whether the site exists. + - dict: Contains information about the existing site. If the + site doesn't exist, this dictionary is empty. + Description: Checks the existence of a site in Cisco Catalyst Center by querying the - 'get_site' function in the 'sites' family. It utilizes the - 'site_name' parameter from the 'want' attribute to identify the site. + 'get_site' function in the 'sites' family. It utilizes the + 'site_name_hierarchy' parameter from the 'want' attribute to identify the site. """ site_exists = False current_site = {} - response = None if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0: - site_name = self.want.get("site_name") - response = self.get_site(site_name) + site_name_hierarchy = self.want.get("site_name_hierarchy") + response = self.get_site_v1(site_name_hierarchy) + if not response: - self.log("No response received from 'get_site' API for site: {0}".format(site_name), "ERROR") - return (site_exists, current_site) + self.log("No response received from 'get_site' API for site: {0}".format(site_name_hierarchy), "ERROR") + return site_exists, current_site - response = response.get("response") - self.log("Received API response from 'get_site': {0}".format(str(response)), "DEBUG") + response_data = response.get("response") + self.log("Received API response from 'get_site': {0}".format(str(response_data)), "DEBUG") - current_site = self.get_current_site(response) + current_site = self.get_current_site(response_data) if current_site: site_exists = True - self.log("Site '{0}' exists in Cisco Catalyst Center".format(site_name), "INFO") + self.log("Site '{0}' exists in Cisco Catalyst Center".format(site_name_hierarchy), "INFO") else: - self.log("No valid site details found for '{0}'".format(site_name), "WARNING") - - return (site_exists, current_site) - + self.log("No valid site details found for '{0}'".format(site_name_hierarchy), "WARNING") + return site_exists, current_site else: try: - response = {} - if self.config[0].get('site', {}).get('bulk_operation', False): - bulk_operation = self.config[0].get('site', {}).get('bulk_operation', False) - else: - bulk_operation = self.config[0]['site']['type'] - + bulk_operation = self.config[0].get('site', {}).get('bulk_operation', False) self.log("Bulk operation mode: {}".format(bulk_operation), "INFO") + if bulk_operation: - name_list = [site["name"] for site in self.want if "name" in site] + name_list = self.get_bulk_site_names(self.config[0]) + self.log("Constructed name_list: {}".format(name_list), "DEBUG") all_sites_info = [] + for name in name_list: try: response = self.get_site(name) - response_data = response.get("response", []) - site_exists = True - if not response_data: + self.log("Raw response from get_site: {}".format(response), "DEBUG") + + if isinstance(response, dict): + sites = response.get("response", []) + elif isinstance(response, list): + self.log("Unexpected list returned from get_site, skipping: {}".format(response), "ERROR") + continue + else: + self.log("Unexpected response type: {}".format(type(response)), "ERROR") + continue + + if not sites: self.log("No site information found for name: {0}".format(name), "WARNING") - return (site_exists, current_site) + continue - for site in response_data: + for site in sites: if isinstance(site, dict): current_site = dict(site.items()) - if site.get('nameHierarchy'): - current_site['parentName'] = site['nameHierarchy'].rsplit('/', 1)[0] - else: - current_site['parentName'] = None - + current_site['parentName'] = site.get('nameHierarchy', '').rsplit('/', 1)[0] if site.get('nameHierarchy') else None all_sites_info.append(current_site) - site_exists = True + + site_exists = True + except Exception as e: self.log("Error fetching site for name '{0}': {1}".format(name, str(e))) - return (site_exists, all_sites_info) + if all_sites_info: + self.log("All site information collected from bulk operation: {}".format(all_sites_info), "DEBUG") + return site_exists, current_site - except Exception as e: - self.log("Bulk operation is not available due to : {0}".format(str(e)), "WARNING") - name_hierarchy = self.want.get("site_name") - try: - response = self.get_site(name_hierarchy) - except Exception as e: - self.log("Error fetching site for {0}: {1}".format(name_hierarchy, str(e))) - response = response.get("response") - if not response: - self.log("No site information found for name hierarchy: {0}".format(name_hierarchy), "WARNING") - return (site_exists, current_site) - - if response: - self.log("Received API response from 'get_sites': {0}".format( - str(response)), "DEBUG") - all_sites_info = [] - for site in response: - if isinstance(site, dict): - current_site = dict(site.items()) - name_hierarchy = site.get('nameHierarchy', '') - if name_hierarchy: - current_site['parentName'] = name_hierarchy.rsplit('/', 1)[0] - else: - current_site['parentName'] = None + site_name_hierarchy = self.want.get("site_name_hierarchy") + site_response = self.get_site(site_name_hierarchy) - all_sites_info.append(current_site) - site_exists = True + if not site_response: + self.log("No site information found for site name hierarchy: {}".format(site_name_hierarchy), "WARNING") + return site_exists, current_site + + response_data = site_response.get("response", []) + self.log("Received API response from 'get_sites': {}".format(response_data), "DEBUG") - return (site_exists, current_site) + for site in response_data: + if isinstance(site, dict): + current_site = dict(site.items()) + site_name_hierarchy = site.get('nameHierarchy', '') + if site_name_hierarchy: + current_site['parentName'] = site_name_hierarchy.rsplit('/', 1)[0] + else: + current_site['parentName'] = None + site_exists = True + + except Exception as e: + self.log("Error during site existence check: {}".format(str(e)), "WARNING") + + return site_exists, current_site def get_parent_id(self, parent_name): """ @@ -718,8 +753,10 @@ def get_site_params(self, params): site_info = {} if typeinfo not in ["area", "building", "floor"]: + self.status = "failed" self.msg = "Given bulk site create playbook is only applicable to DNAC version 2.3.7.6" - self.set_operation_result("failed", False, self.msg, "ERROR") + self.log(self.msg, "ERROR") + self.check_return_status() if typeinfo == 'area': area_details = params.get('site').get('area') @@ -745,7 +782,8 @@ def get_site_params(self, params): 'length': floor_details.get('length'), 'width': floor_details.get('width'), 'height': floor_details.get('height'), - 'floorNumber': floor_details.get('floor_number', '') + 'floorNumber': floor_details.get('floor_number', ''), + 'unitsOfMeasure': floor_details.get('units_of_measure') } if isinstance(floor_details, dict): @@ -763,22 +801,25 @@ def get_site_params(self, params): self.log("Site parameters: {0}".format(str(site_params)), "DEBUG") return site_params - def get_site_name(self, site): + def get_site_name_hierarchy(self, site): """ - Get and Return the site name. + Get and return the site name for a single site. + Parameters: - self (object): An instance of a class used for interacting with Cisco Catalyst Center. - site (dict): A dictionary containing information about the site. + Returns: - - str: The constructed site name. + - str: The constructed site name or None if not found. + Description: - This method takes a dictionary 'site' containing information about - the site and constructs the site name by combining the parent name - and site name. + This method constructs the site name by combining the parent name and site name. + It handles single site operations based on the Cisco DNAC version. """ try: self.log("Retrieving site name for site data: {}".format(site), "DEBUG") site_type = site.get("type") + parent_name = site.get("site", {}).get(site_type, {}).get("parent_name") self.log("Identified site type: {}".format(site_type), "DEBUG") self.log("Retrieved parent name: {}".format(parent_name), "DEBUG") @@ -797,13 +838,82 @@ def get_site_name(self, site): self.set_operation_result("failed", False, self.msg, "ERROR") return None - site_name = '/'.join([parent_name, name]) - self.log("Constructed site name: {}".format(site_name), "INFO") - return site_name + site_name_hierarchy = '/'.join([parent_name, name]) + self.log("Constructed site name: {}".format(site_name_hierarchy), "INFO") + return site_name_hierarchy except Exception as e: - error_message = "An error occurred while getting site name: {0}".format(str(e)) + error_message = "An error occurred while getting site name: {}".format(str(e)) self.log(error_message, "ERROR") + return None + + def get_bulk_site_names(self, site, bulk_operation=True): + """ + Collects and returns a list of constructed site names for areas, buildings, and floors. + + Parameters: + - self (object): An instance of a class used for interacting with Cisco Catalyst Center. + - site (dict): Configuration for a site in Cisco Catalyst Center. + - bulk_operation (bool, optional): Flag to indicate bulk operation mode. Default is True. + + Returns: + - list: A list of constructed site names (e.g., area/building/floor), or an empty list if none are found. + + Description: + This method constructs site names from areas, buildings, and floors defined in the configuration, + based on the Cisco Catalyst Center version. It logs missing hierarchy information as errors. + """ + name_list = [] + self.log("Starting bulk site names construction with arguments - site: {}, bulk_operation: {}".format(site, bulk_operation), "DEBUG") + + if not self.config or not isinstance(self.config, list) or not self.config[0].get('site'): + self.log("Configuration data for sites is missing or improperly formatted.", "ERROR") + return name_list + + try: + self.log("Processing areas for site names.", "DEBUG") + for area in self.config[0].get('site', {}).get('area', []): + area_name = area.get('name') + area_parent_name_hierarchy = area.get('parent_name_hierarchy') + if area_name and area_parent_name_hierarchy: + constructed_name = "{}/{}".format(area_parent_name_hierarchy, area_name) + name_list.append(constructed_name) + self.log("Constructed area name: {}".format(constructed_name), "DEBUG") + elif not area_parent_name_hierarchy: + self.log("Missing parent name hierarchy for area: {}".format(area_name), "ERROR") + + self.log("Processing buildings for site names.", "DEBUG") + for building in self.config[0].get('site', {}).get('building', []): + building_name = building.get('name') + building_parent_name_hierarchy = building.get('parent_name_hierarchy') + if building_name and building_parent_name_hierarchy: + constructed_name = "{}/{}".format(building_parent_name_hierarchy, building_name) + name_list.append(constructed_name) + self.log("Constructed building name: {}".format(constructed_name), "DEBUG") + elif not building_parent_name_hierarchy: + self.log("Missing parent name hierarchy for building: {}".format(building_name), "ERROR") + + self.log("Processing floors for site names.", "DEBUG") + for floor in self.config[0].get('site', {}).get('floor', []): + floor_name = floor.get('name') + floor_parent_name_hierarchy = floor.get('parent_name_hierarchy') + if floor_name and floor_parent_name_hierarchy: + constructed_name = "{}/{}".format(floor_parent_name_hierarchy, floor_name) + name_list.append(constructed_name) + self.log("Constructed floor name: {}".format(constructed_name), "DEBUG") + elif not floor_parent_name_hierarchy: + self.log("Missing parent name hierarchy for floor: {}".format(floor_name), "ERROR") + + if not name_list: + self.log("No site names constructed from areas, buildings, or floors.", "WARNING") + else: + self.log("Final constructed site names: {}".format(name_list), "DEBUG") + self.log("Bulk site names construction completed successfully.", "DEBUG") + + except Exception as e: + self.log("An error occurred while constructing site names: {}".format(str(e)), "ERROR") + + return name_list def compare_float_values(self, ele1, ele2, precision=2): """ @@ -882,17 +992,28 @@ def is_floor_updated(self, updated_site, requested_site): It checks if the name, rf_model, length, width, and height are equal, indicating that the floor details have been updated. Returns True if the details match, and False otherwise. """ - + self.log("Starting floor update check with updated_site: {} and requested_site: {}".format(updated_site, requested_site), "DEBUG") keys_to_compare = ['length', 'width', 'height'] - if updated_site['name'] != requested_site['name'] or updated_site.get('rf_model') != requested_site.get('rfModel'): + if updated_site['name'] != requested_site['name']: + self.log("Floor names do not match: updated '{}', requested '{}'".format(updated_site['name'], requested_site['name']), "DEBUG") return False - if requested_site.get('floorNumber') and int(requested_site.get('floorNumber')) != int(updated_site.get('floorNumber')): + updated_rf_model = updated_site.get('rfModel', updated_site.get('rf_model')) + if updated_rf_model != requested_site.get('rfModel'): + self.log("RF model mismatch: updated '{}', requested '{}'".format(updated_rf_model, requested_site.get('rfModel')), "DEBUG") return False + if requested_site.get('floorNumber'): + if int(requested_site.get('floorNumber')) != int(updated_site.get('floorNumber')): + self.log( + "Floor number mismatch: updated '{}', requested '{}'".format(updated_site.get('floorNumber'), requested_site.get('floorNumber')), "DEBUG") + return False + for key in keys_to_compare: if not self.compare_float_values(updated_site[key], requested_site[key]): + self.log("Mismatch in '{}': updated '{}', requested '{}'".format(key, updated_site[key], requested_site[key]), "DEBUG") return False + self.log("Floor details match between updated and requested site.", "DEBUG") return True def site_requires_update(self): @@ -945,7 +1066,6 @@ def site_requires_update(self): def get_have(self, config): """ Get the site details from Cisco Catalyst Center. - Parameters: - self (object): An instance of a class used for interacting with Cisco Catalyst Center. - config (dict): A dictionary containing the configuration details. @@ -971,8 +1091,10 @@ def get_have(self, config): if site_exists: have["site_exists"] = site_exists have["current_site"] = current_site + have["site_id"] = current_site.get("id") self.log("Site details found in Cisco Catalyst Center: {}".format(current_site), "DEBUG") else: + have["site_id"] = current_site.get("id") self.log("No site found in Cisco Catalyst Center.", "WARNING") site_exists, current_site = self.site_exists() self.log("Regular operation: Retrieved site existence: {}".format(site_exists), "DEBUG") @@ -980,7 +1102,7 @@ def get_have(self, config): if site_exists: if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0: have["site_id"] = current_site.get("siteId") - self.log("Using legacy siteId for site version <= 2.3.5.3: {}".format(have["site_id"]), "DEBUG") + self.log("SiteId for site version <= 2.3.5.3: {}".format(have["site_id"]), "DEBUG") else: have["site_id"] = current_site.get("id") self.log("Using updated site ID for newer version: {}".format(have["site_id"]), "DEBUG") @@ -1008,7 +1130,7 @@ def get_want(self, config): Description: Retrieves all site-related information from playbook that is required for creating a site in Cisco Catalyst Center. It includes - parameters such as 'site_params' and 'site_name.' The gathered + parameters such as 'site_params' and 'site_name_hierarchy.' The gathered information is stored in the 'want' attribute for later reference. """ try: @@ -1070,13 +1192,13 @@ def get_want(self, config): want = dict( site_params=self.get_site_params(config), - site_name=self.get_site_name(config), + site_name_hierarchy=self.get_site_name_hierarchy(config), ) self.want = want - self.log("Desired State (want): {0}".format(self.pprint(self.want)), "INFO") + self.log("Desired State (want): {0}".format(self.want), "INFO") return self - def update_floor(self, site_params): + def update_floor(self, site_params, config): """ Updates a floor in the site hierarchy using the provided site parameters. @@ -1088,15 +1210,45 @@ def update_floor(self, site_params): dict: The API response from the 'updates_a_floor' operation or None if an exception occurs. """ response = None - units_of_measure = "feet" + units_of_measure = ["feet", "meters"] + rf_model = [ + "Free Space", + "Outdoor Open Space", + "Cubes And Walled Offices", + "Indoor High Ceiling", + "Drywall Office Only" + ] try: self.log("Updating floor with parameters: {0}".format(site_params), "INFO") parent_name = site_params.get("site", {}).get("floor", {}).get("parentName") + if not parent_name: + self.log("Parent name is missing in the site parameters.", "ERROR") + return None parent_id = self.get_parent_id(parent_name) + if not parent_id: + self.log("Failed to retrieve parent ID for parent name: '{}'".format(parent_name), "ERROR") + return None site_params['site']['floor']['parentId'] = parent_id - site_params['site']['floor']['unitsOfMeasure'] = units_of_measure + self.log("Retrieved parent ID: '{}' for parent name: '{}'".format(parent_id, parent_name), "DEBUG") + + units_of_measure_value = config.get("site", {}).get("floor", {}).get("units_of_measure") + if units_of_measure_value not in units_of_measure: + error_msg = "Given Unit of Measure: {} not in allowed units: {}".format(units_of_measure_value, units_of_measure) + self.module.fail_json(msg=error_msg) + else: + site_params['site']['floor']['unitsOfMeasure'] = units_of_measure_value + self.log("Set 'units of measure' to: {}".format(units_of_measure_value), "DEBUG") + + rf_model_value = site_params.get('site', {}).get('floor', {}).get('rfModel') + if rf_model_value not in rf_model: + error_msg = "Given RF Model: {} not in valid models: {}".format(rf_model_value, rf_model) + self.module.fail_json(msg=error_msg) + else: + self.log("Validated 'RF Model' as: {}".format(rf_model_value), "DEBUG") + self.log("Updated site_params with parent_id: {0}".format(site_params), "INFO") floor_param = site_params.get('site', {}).get('floor') + site_params['site']['floor']['parentId'] = parent_id site_id = self.have.get("site_id") floor_param['id'] = site_id @@ -1163,7 +1315,7 @@ def update_building(self, site_params): return response except Exception as e: - self.msg = "Exception occurred while updating building '{0}' due to: {1}".format(site_params.get('site_name'), str(e)) + self.msg = "Exception occurred while updating building '{0}' due to: {1}".format(site_params.get('site_name_hierarchy'), str(e)) self.result['response'] = self.msg self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() @@ -1179,13 +1331,13 @@ def update_area(self, site_params): """ response = None try: - self.log("Updating area with parameters: {0}".format( - site_params), "INFO") - parent_id = self.have.get("parent_id") + self.log("Updating area with parameters: {0}".format(self.have), "INFO") + parent_id = self.have.get("current_site", {}).get("parentId") site_params['site']['area']['parentId'] = parent_id area_param = site_params.get('site', {}).get('area') site_id = self.have.get("site_id") area_param['id'] = site_id + self.log("Updating area with parameters: {0}".format(area_param), "INFO") response = self.dnac._exec( family="site_design", @@ -1199,7 +1351,7 @@ def update_area(self, site_params): return response except Exception as e: - self.msg = "Exception occurred while updating area'{0}' due to: {1}".format(site_params.get('site_name'), str(e)) + self.msg = "Exception occurred while updating area'{0}' due to: {1}".format(site_params.get('site_name_hierarchy'), str(e)) self.result['response'] = self.msg self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() @@ -1232,10 +1384,8 @@ def creating_bulk_site(self): return response except Exception as e: - error_msg = "Exception occurred while creating site due to: {}".format(str(e)) - self.log(error_msg, "ERROR") - self.status = "failed" - self.check_return_status() + self.msg = "Exception occurred while creating site due to: {}".format(str(e)) + self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() def get_diff_merged(self, config): """ @@ -1276,6 +1426,23 @@ def get_diff_merged(self, config): name_list = [site.get("name") for site in self.want if "name" in site] self.created_site_list.append(name_list) self.log("Site '{}' created successfully".format(name_list), "INFO") + + for site in self.want: + if site.get("type") == "floor": + floor_name = site.get("name") + self.log("Floor '{}' has been created successfully.".format(floor_name), "INFO") + + upload_path = site.get("upload_floor_image_path", None) + if upload_path: + self.log( + "Upload path found for floor '{}'. Starting upload floor map from '{}.'".format(floor_name, upload_path), "INFO") + map_details, map_status, success_message = self.upload_floor_image(config) + if map_details: + self.log("Floor map for '{}' uploaded successfully: {}".format(floor_name, success_message), "INFO") + else: + self.log("Floor map upload failed for '{}'. Please check the upload path and retry.".format(floor_name), "ERROR") + else: + self.log("No upload path provided for '{}'. Floor created without floor map.".format(floor_name), "INFO") return self self.log("No valid task ID received from the 'creating_bulk_site' response.", "WARNING") return None @@ -1285,9 +1452,14 @@ def get_diff_merged(self, config): self.log("Yaml is not available for bulk: {}".format(e), "ERROR") if self.have.get("site_exists"): - site_name = self.want.get("site_name") + site_name_hierarchy = self.want.get("site_name_hierarchy") + if not self.site_requires_update(): + self.update_not_needed_sites.append(site_name_hierarchy) + self.msg = "Site - {0} does not need any update".format(site_name_hierarchy) + self.log(self.msg, "INFO") + return self - if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0 and self.site_requires_update(): + if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0: try: site_params = self.want.get("site_params") site_params["site_id"] = self.have.get("site_id") @@ -1301,81 +1473,71 @@ def get_diff_merged(self, config): params=site_params, ) self.log("Received API response from 'update_site': {0}".format(str(response)), "DEBUG") - site_updated = True + + if response and isinstance(response, dict): + execution_id = response.get("executionId") + while True: + execution_details = self.get_execution_details(execution_id) + if execution_details.get("status") == "SUCCESS": + self.result['changed'] = True + site_updated = True + self.updated_site_list.append(site_name_hierarchy) + self.log("Site - {0} Updated Successfully".format(site_name_hierarchy), "INFO") + break + elif execution_details.get("bapiError"): + self.module.fail_json(msg=execution_details.get( + "bapiError"), response=execution_details) + except Exception as e: self.log("Unexpected error occurred: {0}".format(str(e)), "ERROR") - error_message = "Site - {0} does not need any update".format(site_name) + error_message = "Site - {0} does not need any update".format(site_name_hierarchy) return {"error_message": error_message} - if not self.site_requires_update(): - self.update_not_needed_sites.append(site_name) - self.log("Site - {0} does not need any update".format(site_name), "INFO") - - return self + site_exists, current_site = self.site_exists() + if site_exists: + self.update_not_needed_sites.append(site_name_hierarchy) + self.log("Site '{0}' created successfully".format(site_name_hierarchy), "INFO") - if site_updated and response and isinstance(response, dict): - execution_id = response.get("executionId") - while True: - execution_details = self.get_execution_details(execution_id) - if execution_details.get("status") == "SUCCESS": - self.result['changed'] = True - break - elif execution_details.get("bapiError"): - self.module.fail_json(msg=execution_details.get( - "bapiError"), response=execution_details) - break - - if site_updated: - self.updated_site_list.append(site_name) - self.log("Site - {0} Updated Successfully".format(site_name), "INFO") - - else: - site_exists = self.site_exists() - if site_exists: - self.created_site_list.append(site_name) - self.log("Site '{0}' created successfully".format(site_name), "INFO") - - elif self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.6") >= 0 and self.site_requires_update(): + elif self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.6") >= 0: site_params = self.want.get("site_params") site_params["site_id"] = self.have.get("site_id") site_type = site_params.get("type") + self.log(site_name_hierarchy) + if self.site_requires_update(): + response = (self.update_floor(site_params, config) if site_type == "floor" + else self.update_area(site_params) if site_type == "area" + else self.update_building(site_params) if site_type == "building" + else self.log("Unknown site type: {0}".format(site_type), "ERROR")) - response = (self.update_floor(site_params) if site_type == "floor" - else self.update_area(site_params) if site_type == "area" - else self.update_building(site_params) if site_type == "building" - else self.log("Unknown site type: {0}".format(site_type), "ERROR")) - - if response: self.log("Received API response from 'update_site': {0}".format(str(response)), "DEBUG") - site_updated = True - - if site_updated and response and isinstance(response, dict): - taskid = response["response"]["taskId"] - task_details = self.get_task_details(taskid) - while True: - if site_type != "floor": - if task_details.get("progress") == "Group is updated successfully": - self.result['changed'] = True - self.result['response'] = task_details - break - else: - if task_details.get("progress") == "Service domain is updated successfully.": - self.result['changed'] = True - self.result['response'] = task_details + if response and isinstance(response, dict): + taskid = response["response"]["taskId"] + task_details = self.get_task_details(taskid) + + while True: + if site_type != "floor": + if task_details.get("progress") == "Group is updated successfully": + self.result['changed'] = True + site_updated = True + self.result['response'] = task_details + break + else: + if task_details.get("progress") == "Service domain is updated successfully.": + self.result['changed'] = True + site_updated = True + self.result['response'] = task_details + break + + if task_details.get("bapiError"): + self.module.fail_json(msg=task_details.get("bapiError"), response=task_details) break - - if task_details.get("bapiError"): - self.module.fail_json(msg=task_details.get("bapiError"), response=task_details) - break - else: - self.update_not_needed_sites.append(site_name) - self.log("Site - {0} does not need any update".format(site_name), "INFO") - return self + else: + self.msg = "Unable to execute the update the site: {0} ".format(site_name_hierarchy) + self.log(self.msg, "INFO") + return self else: - self.log(site_updated) - if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0: try: site_params = self.want.get("site_params") @@ -1404,7 +1566,7 @@ def get_diff_merged(self, config): site_created = True except Exception as e: self.log("Unexpected error occurred: {0}".format(str(e)), "ERROR") - error_message = "Failed to create site '{0}': {1}".format(site_name, str(e)) + error_message = "Failed to create site '{0}': {1}".format(site_name_hierarchy, str(e)) return {"error_message": error_message} if (site_created or site_updated) and response and isinstance(response, dict): @@ -1421,9 +1583,9 @@ def get_diff_merged(self, config): site_exists, current_site = self.site_exists() if site_exists: - site_name = self.want.get("site_name") - self.created_site_list.append(site_name) - self.log("Site '{0}' created successfully".format(site_name), "INFO") + site_name_hierarchy = self.want.get("site_name_hierarchy") + self.created_site_list.append(site_name_hierarchy) + self.log("Site '{0}' created successfully".format(site_name_hierarchy), "INFO") return self else: self.msg = "This version : '{0}' given yaml format is not applicable to create a site' ".format( @@ -1431,23 +1593,23 @@ def get_diff_merged(self, config): self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() if site_updated: - self.updated_site_list.append(site_name) - self.log("Site - {0} Updated Successfully".format(site_name), "INFO") + self.updated_site_list.append(site_name_hierarchy) + self.log("Site {0} Updated Successfully".format(site_name_hierarchy), "INFO") else: site_exists, current_site = self.site_exists() if site_exists: - self.created_site_list.append(site_name) - self.log("Site '{0}' created successfully".format(site_name), "INFO") + self.created_site_list.append(site_name_hierarchy) + self.log("Site '{0}' created successfully".format(site_name_hierarchy), "INFO") return self - def delete_single_site(self, site_id, site_name): + def delete_single_site(self, site_id, site_name_hierarchy): """" Delete a single site in the Cisco Catalyst Center. Parameters: self (object): An instance of a class used for interacting with Cisco Catalyst Center. site_id (str): The ID of the site to be deleted. - site_name (str): The name of the site to be deleted. + site_name_hierarchy (str): The name of the site to be deleted. Returns: self (object): An instance of a class used for interacting with Cisco Catalyst Center. Description: @@ -1471,8 +1633,8 @@ def delete_single_site(self, site_id, site_name): execution_details = self.get_execution_details(executionid) if execution_details.get("status") == "SUCCESS": self.status = "success" - self.deleted_site_list.append(site_name) - self.log("Site '{0}' deleted successfully".format(site_name), "INFO") + self.deleted_site_list.append(site_name_hierarchy) + self.log("Site '{0}' deleted successfully".format(site_name_hierarchy), "INFO") break elif execution_details.get("bapiError"): self.log("Error response for 'delete_site' execution: {0}".format( @@ -1482,53 +1644,62 @@ def delete_single_site(self, site_id, site_name): break except Exception as e: - self.msg = "Exception occurred while deleting site '{0}' due to: {1}".format(site_name, str(e)) + self.msg = "Exception occurred while deleting site '{0}' due to: {1}".format(site_name_hierarchy, str(e)) self.set_operation_result("failed", False, self.msg, "ERROR") return self - def delete_floor(self, site_name): + def delete_floor(self, site_name_hierarchy): """ Deletes a floor site by ID. Parameters: site_id (str): The ID of the floor site to be deleted. - site_name (str): The name of the floor site to be deleted. + site_name_hierarchy (str): The name of the floor site to be deleted. Returns: dict: The API response from the 'deletes_a_floor' operation. """ site_id = self.have.get("site_id") + + if not site_id: + self.log("No site ID found for building site: '{}'.".format(site_name_hierarchy), "ERROR") + return None try: self.log( - "Deleting floor site: {0} with ID: {1}".format(site_name, site_id), "INFO") + "Deleting floor site: {0} with ID: {1}".format(site_name_hierarchy, site_id), "INFO") response = self.dnac._exec( family="site_design", function="deletes_a_floor", op_modifies=True, params={'id': site_id}, ) - self.log("Successfully deleted floor site: {0}. API response: {1}".format(site_name, response), "DEBUG") + self.log("Successfully deleted floor site: {0}. API response: {1}".format(site_name_hierarchy, response), "DEBUG") return response except Exception as e: - self.msg = "Exception occurred while deleting floor site '{0}' with site_id '{1}' due to: {2}".format(site_name, site_id, str(e)) + self.msg = "Exception occurred while deleting floor site '{0}' with site_id '{1}' due to: {2}".format(site_name_hierarchy, site_id, str(e)) self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() - def delete_building(self, site_name): + def delete_building(self, site_name_hierarchy): """ Deletes a building site by ID. Parameters: site_id (str): The ID of the building site to be deleted. - site_name (str): The name of the building site to be deleted. + site_name_hierarchy (str): The name of the building site to be deleted. Returns: dict: The API response from the 'deletes_a_building' operation. """ site_id = self.have.get("site_id") + + if not site_id: + self.log("No site ID found for building site: '{}'.".format(site_name_hierarchy), "ERROR") + return None + try: - self.log("Deleting building site: {0} with ID: {1}".format(site_name, site_id), "INFO") + self.log("Deleting building site '{0}' with ID: '{1}'".format(site_name_hierarchy, site_id), "INFO") response = self.dnac._exec( family="site_design", @@ -1536,38 +1707,43 @@ def delete_building(self, site_name): op_modifies=True, params={'id': site_id}, ) - self.log("Successfully deleted building site: {0}. API response: {1}".format(site_name, response), "DEBUG") + self.log("Successfully deleted building site: {0}. API response: {1}".format(site_name_hierarchy, response), "DEBUG") return response except Exception as e: - self.msg = "Exception occurred while deleting building site '{0}' with site_id '{1}' due to: {2}".format(site_name, site_id, str(e)) + self.msg = "Exception occurred while deleting building site '{0}' with site_id '{1}' due to: {2}".format(site_name_hierarchy, site_id, str(e)) self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() - def delete_area(self, site_name): + def delete_area(self, site_name_hierarchy): """ Deletes an area site by ID. Parameters: site_id (str): The ID of the site to be deleted. - site_name (str): The name of the site to be deleted. + site_name_hierarchy (str): The name of the site to be deleted. Returns: self: An instance of the class used for interacting with Cisco Catalyst Center. """ site_id = self.have.get("site_id") + + if not site_id: + self.log("No site ID found for building site: '{}'.".format(site_name_hierarchy), "ERROR") + return None + try: - self.log("Deleting area site: {0} with ID: {1}".format(site_name, site_id), "INFO") + self.log("Deleting area site: {0} with ID: {1}".format(site_name_hierarchy, site_id), "INFO") response = self.dnac._exec( family="site_design", function="deletes_an_area", op_modifies=True, params={'id': site_id}, ) - self.log("Successfully deleted farea site: {0}. API response: {1}".format(site_name, response), "DEBUG") + self.log("Successfully deleted farea site: {0}. API response: {1}".format(site_name_hierarchy, response), "DEBUG") return response except Exception as e: - self.msg = "Exception occurred while deleting area site '{0}' with site_id '{1}' due to: {2}".format(site_name, site_id, str(e)) + self.msg = "Exception occurred while deleting area site '{0}' with site_id '{1}' due to: {2}".format(site_name_hierarchy, site_id, str(e)) self.set_operation_result("failed", False, self.msg, "ERROR").check_return_status() def get_diff_deleted(self, config): @@ -1588,27 +1764,29 @@ def get_diff_deleted(self, config): of the Cisco Catalyst Center API. It uses the site ID obtained from the 'have' attribute. """ site_exists = self.have.get("site_exists") - site_name = self.want.get("site_name") + site_name_hierarchy = self.want.get("site_name_hierarchy") if not site_exists: self.status = "success" + # self.site_absent_list.append(site_name) self.log( - "Unable to delete site '{0}' as it's not found in Cisco Catalyst Center".format(self.want.get("site_name")), "INFO") + "Unable to delete site '{0}' as it's not found in Cisco Catalyst Center".format(self.want.get("site_name_hierarchy")), "INFO") return self if self.compare_dnac_versions(self.get_ccc_version(), "2.3.5.3") <= 0: site_id = self.have.get("site_id") - api_response, response = self.get_device_ids_from_site(site_name, site_id) + site_name_hierarchy = self.want.get("site_name_hierarchy") + api_response, response = self.get_device_ids_from_site(site_name_hierarchy, site_id) self.log( "Received API response from 'get_membership': {0}".format(str(api_response)), "DEBUG") site_response = api_response.get("site", {}).get("response", []) self.log( - "Site '{0}' response along with its child sites: {1}".format(site_name, str(site_response)), "DEBUG") + "Site '{0}' response along with its child sites: {1}".format(site_name_hierarchy, str(site_response)), "DEBUG") if not site_response: - self.delete_single_site(site_id, site_name) + self.delete_single_site(site_id, site_name_hierarchy) return self sorted_site_resp = sorted( @@ -1617,45 +1795,35 @@ def get_diff_deleted(self, config): for item in sorted_site_resp: self.delete_single_site(item['id'], item['name']) - self.delete_single_site(site_id, site_name) + self.delete_single_site(site_id, site_name_hierarchy) self.log( - "The site '{0}' and its child sites have been deleted successfully".format(site_name), "INFO") + "The site '{0}' and its child sites have been deleted successfully".format(site_name_hierarchy), "INFO") elif self.compare_dnac_versions(self.get_ccc_version(), "2.3.7.6") >= 0: site_params = self.want.get("site_params") site_params["site_id"] = self.have.get("site_id") site_type = site_params.get("type") site_id = self.have.get("site_id") - - response = self.get_site(site_id) + self.log("Site ID from 'have' for retrieval: {0}".format(site_id), "DEBUG") + self.log("Site TYPE from 'have' for retrieval: {0}".format(site_type), "DEBUG") + self.log("Site PARAMS from 'have' for retrieval: {0}".format(site_params), "DEBUG") + self.log("Site NAME from 'want' for retrieval: {0}".format(site_name_hierarchy), "DEBUG") + site_hierarchy = self.want.get("site_name_hierarchy") + self.log("Initiating deletion for site '{}' with site ID: {} of type: {}".format(site_name_hierarchy, site_id, site_type), "DEBUG") + response = self.get_site(site_hierarchy) self.log("Received API response from 'get_site_assigned_network_devices': {0}".format(str(response)), "DEBUG") site_response = response.get("response", []) - if site_response: - self.module.fail_json( - msg=( - "Site '{0}' cannot be deleted because it has assigned devices. " - "Please delete devices first then delete the site.".format(site_name) - ) - ) - - return self - response = None if site_type == "floor": - response = self.delete_floor(site_name) + response = self.delete_floor(site_name_hierarchy) elif site_type == "area": - response = self.delete_area(site_name) - self.log( - "Manual test response for deleting area: {0}".format(str(response)), "DEBUG") + response = self.delete_area(site_name_hierarchy) + self.log("Response for deleting area: {0}".format(str(response)), "DEBUG") elif site_type == "building": - response = self.delete_building(site_name) - - self.log( - "Received API response from 'deleted': {0}".format(str(response)), "DEBUG") - site_deleted = response is not None + response = self.delete_building(site_name_hierarchy) - if site_deleted and isinstance(response, dict): + if isinstance(response, dict): taskid = response.get("response", {}).get("taskId") if taskid: @@ -1663,11 +1831,10 @@ def get_diff_deleted(self, config): while True: if site_type != "floor": if task_details.get("progress") == "Group is deleted successfully": - self.log( - "Area site '{0}' deleted successfully.".format(site_name), "INFO") + self.log("Area site '{0}' deleted successfully.".format(site_name_hierarchy), "INFO") self.result['changed'] = True self.result['response'] = task_details - self.deleted_site_list.append(site_name) + self.deleted_site_list.append(site_name_hierarchy) break elif task_details.get("failureReason"): self.log( @@ -1677,10 +1844,10 @@ def get_diff_deleted(self, config): break else: if task_details.get("progress") == "NCMP00150: Service domain is deleted successfully": - self.log("Area site '{0}' deleted successfully.".format(site_name), "INFO") + self.log("Area site '{0}' deleted successfully.".format(site_name_hierarchy), "INFO") self.result['changed'] = True self.result['response'] = task_details - self.deleted_site_list.append(site_name) + self.deleted_site_list.append(site_name_hierarchy) break elif task_details.get("failureReason"): self.log("Error response for 'deletes_an_area' task: {0}".format(task_details.get('failureReason')), "ERROR") @@ -1721,25 +1888,25 @@ def verify_diff_merged(self, config): self.get_have(config) site_exist = self.have.get("site_exists") - site_name = self.want.get("site_name") + site_name_hierarchy = self.want.get("site_name_hierarchy") self.log("Current State (have): {0}".format(str(self.have)), "INFO") self.log("Desired State (want): {0}".format(str(self.want)), "INFO") if site_exist: self.status = "success" - self.msg = "The requested site '{0}' is present in the Cisco Catalyst Center and its creation has been verified.".format(site_name) + self.msg = "The requested site '{0}' is present in the Cisco Catalyst Center and its creation has been verified.".format(site_name_hierarchy) self.log(self.msg, "INFO") require_update = self.site_requires_update() if not require_update: - self.log("The update for site '{0}' has been successfully verified.".format(site_name), "INFO") + self.log("The update for site '{0}' has been successfully verified.".format(site_name_hierarchy), "INFO") self.status = "success" return self self.log("""The playbook input for site '{0}' does not align with the Cisco Catalyst Center, indicating that the merge task - may not have executed successfully.""".format(site_name), "INFO") + may not have executed successfully.""".format(site_name_hierarchy), "INFO") return self @@ -1763,15 +1930,95 @@ def verify_diff_deleted(self, config): if not site_exist: self.status = "success" msg = """The requested site '{0}' has already been deleted from the Cisco Catalyst Center and this has been - successfully verified.""".format(self.want.get("site_name")) + successfully verified.""".format(self.want.get("site_name_hierarchy")) self.log(msg, "INFO") return self self.log("""Mismatch between the playbook input for site '{0}' and the Cisco Catalyst Center indicates that - the deletion was not executed successfully.""".format(self.want.get("site_name")), "INFO") + the deletion was not executed successfully.""".format(self.want.get("site_name_hierarchy")), "INFO") + return self + + def update_site_messages(self): + """ + Update site messages based on the status of created, updated, and deleted sites. + Args: + self (object): An instance of a class used for interacting with Cisco Catalyst Center. + Returns: + self (object): An instance of a class representing the status of the operation, including whether it was + successful or failed, any error messages encountered during operation. + Description: + This method updates the messages related to site creation, updating, and deletion in the Cisco Catalyst Center. + It evaluates the status of created sites, updated sites, and sites that are no longer needed for update to + determine the appropriate message to be set. The messages are then stored in the 'msg' attribute of the object. + """ + if self.created_site_list and self.updated_site_list: + self.result['changed'] = True + if self.update_not_needed_sites: + msg = """Site(s) '{0}' created successfully as well as Site(s) '{1}' updated successully and the some site(s) + '{2}' needs no update in Cisco Catalyst Center""" + self.msg = msg.format(str(self.created_site_list), str( + self.updated_site_list), str(self.update_not_needed_sites)) + else: + self.msg = """Site(s) '{0}' created successfully in Cisco Catalyst Center as well as Site(s) '{1}' updated successully in + Cisco Catalyst Center""".format(str(self.created_site_list), str(self.updated_site_list)) + elif self.created_site_list: + self.result['changed'] = True + if self.update_not_needed_sites: + self.msg = """Site(s) '{0}' created successfully and some site(s) '{1}' not needs any update in Cisco Catalyst + Center.""".format(str(self.created_site_list), str(self.update_not_needed_sites)) + else: + self.msg = "Site(s) '{0}' created successfully in Cisco Catalyst Center.".format( + str(self.created_site_list)) + elif self.updated_site_list: + self.result['changed'] = True + if self.update_not_needed_sites: + self.msg = """Site(s) '{0}' updated successfully and some site(s) '{1}' not needs any update in Cisco Catalyst + Center.""".format(str(self.updated_site_list), str(self.update_not_needed_sites)) + else: + self.msg = "Site(s) '{0}' updated successfully in Cisco Catalyst Center.".format( + str(self.updated_site_list)) + elif self.update_not_needed_sites: + self.result['changed'] = False + self.msg = "Site(s) '{0}' not needs any update in Cisco Catalyst Center.".format( + str(self.update_not_needed_sites)) + elif self.deleted_site_list and self.site_absent_list: + self.result['changed'] = True + self.msg = """Given site(s) '{0}' deleted successfully from Cisco Catalyst Center and unable to deleted some site(s) '{1}' as they + are not found in Cisco Catalyst Center.""".format(str(self.deleted_site_list), str(self.site_absent_list)) + elif self.deleted_site_list: + self.result['changed'] = True + self.msg = "Given site(s) '{0}' deleted successfully from Cisco Catalyst Center".format( + str(self.deleted_site_list)) + else: + self.result['changed'] = False + self.msg = "Unable to delete site(s) '{0}' as it's not found in Cisco Catalyst Center.".format( + str(self.site_absent_list)) + + self.status = "success" + self.result['response'] = self.msg + self.result['msg'] = self.msg + return self def upload_floor_image(self, config): + """ + Upload a floor image to the Cisco Catalyst Center. + + Args: + self (object): An instance of a class used for interacting with Cisco Catalyst Center. + config (dict): A dictionary containing configuration details, including the file path for the floor image. + + Returns: + tuple: A tuple containing: + - map_details (bool): Indicates if the upload was successful. + - map_status (dict or None): Contains the upload status if successful; otherwise None. + - success_message (str or None): A success message if upload was successful; otherwise None. + + Description: + This method uploads a specified floor image by validating the file path, ensuring the file exists, + determining the content type, reading the file content, and invoking the appropriate API to upload the image. + It logs the success or failure of the upload operation. + """ map_details = None map_status = None response = None @@ -1786,18 +2033,23 @@ def upload_floor_image(self, config): file_path = config['site']['floor'][0]['upload_floor_image_path'] self.log("File path extracted from config: {}".format(file_path), "DEBUG") + if not isinstance(file_path, str) or not file_path: + raise ValueError("Invalid file path format. It must be a non-empty string.") if not os.path.exists(file_path): raise ValueError("File path does not exist: {}".format(file_path)) self.log("File path exists: {}".format(file_path), "DEBUG") + valid_extensions = ['.png', '.jpg', '.jpeg', '.pdf'] + if not any(file_path.lower().endswith(ext) for ext in valid_extensions): + raise ValueError("Unsupported file format. Supported formats: {}".format(", ".join(valid_extensions))) + if file_path.lower().endswith('.png'): content_type = 'image/png' elif file_path.lower().endswith('.jpg') or file_path.lower().endswith('.jpeg'): content_type = 'image/jpeg' elif file_path.lower().endswith('.pdf'): content_type = 'application/pdf' - else: - raise ValueError("Unsupported file format.") + self.log("Determined content type: {}".format(content_type), "DEBUG") try: @@ -1809,6 +2061,7 @@ def upload_floor_image(self, config): site_id = self.have.get("site_id") if not site_id: raise ValueError("No valid site_id found in 'self.have'.") + multipart_fields = { 'image': (os.path.basename(file_path), file_content, content_type) } @@ -1834,7 +2087,6 @@ def upload_floor_image(self, config): self.log(self.msg, "ERROR") self.module.fail_json(msg=self.msg) return None, None, None - else: raise ValueError("DNAC version is below the required version for this function.") @@ -1857,68 +2109,6 @@ def upload_floor_image(self, config): return map_details, map_status, success_message - def update_site_messages(self): - """ - Update site messages based on the status of created, updated, and deleted sites. - Args: - self (object): An instance of a class used for interacting with Cisco Catalyst Center. - Returns: - self (object): An instance of a class representing the status of the operation, including whether it was - successful or failed, any error messages encountered during operation. - Description: - This method updates the messages related to site creation, updating, and deletion in the Cisco Catalyst Center. - It evaluates the status of created sites, updated sites, and sites that are no longer needed for update to - determine the appropriate message to be set. The messages are then stored in the 'msg' attribute of the object. - """ - if self.created_site_list and self.updated_site_list: - self.result['changed'] = True - if self.update_not_needed_sites: - msg = """Site(s) '{0}' created successfully as well as Site(s) '{1}' updated successully and the some site(s) - '{2}' needs no update in Cisco Catalyst Center""" - self.msg = msg.format(str(self.created_site_list), str( - self.updated_site_list), str(self.update_not_needed_sites)) - else: - self.msg = """Site(s) '{0}' created successfully in Cisco Catalyst Center as well as Site(s) '{1}' updated successully in - Cisco Catalyst Center""".format(str(self.created_site_list), str(self.updated_site_list)) - elif self.created_site_list: - self.result['changed'] = True - if self.update_not_needed_sites: - self.msg = """Site(s) '{0}' created successfully and some site(s) '{1}' not needs any update in Cisco Catalyst - Center.""".format(str(self.created_site_list), str(self.update_not_needed_sites)) - else: - self.msg = "Site(s) '{0}' created successfully in Cisco Catalyst Center.".format( - str(self.created_site_list)) - elif self.updated_site_list: - self.result['changed'] = True - if self.update_not_needed_sites: - self.msg = """Site(s) '{0}' updated successfully and some site(s) '{1}' not needs any update in Cisco Catalyst - Center.""".format(str(self.updated_site_list), str(self.update_not_needed_sites)) - else: - self.msg = "Site(s) '{0}' updated successfully in Cisco Catalyst Center.".format( - str(self.updated_site_list)) - elif self.update_not_needed_sites: - self.result['changed'] = False - self.msg = "Site(s) '{0}' not needs any update in Cisco Catalyst Center.".format( - str(self.update_not_needed_sites)) - elif self.deleted_site_list and self.site_absent_list: - self.result['changed'] = True - self.msg = """Given site(s) '{0}' deleted successfully from Cisco Catalyst Center and unable to deleted some site(s) '{1}' as they - are not found in Cisco Catalyst Center.""".format(str(self.deleted_site_list), str(self.site_absent_list)) - elif self.deleted_site_list: - self.result['changed'] = True - self.msg = "Given site(s) '{0}' deleted successfully from Cisco Catalyst Center".format( - str(self.deleted_site_list)) - else: - self.result['changed'] = False - self.msg = "Unable to delete site(s) '{0}' as it's not found in Cisco Catalyst Center.".format( - str(self.site_absent_list)) - - self.status = "success" - self.result['response'] = self.msg - self.result['msg'] = self.msg - - return self - def main(): """ main entry point for module execution @@ -1969,16 +2159,16 @@ def main(): for config in ccc_site.validated_config: ccc_site.reset_values() + ccc_site.get_want(config).check_return_status() ccc_site.get_have(config).check_return_status() - ccc_site.upload_floor_image(config) + ccc_site.get_diff_state_apply[state](config).check_return_status() + if config_verify: - ccc_site.verify_diff_state_apply[state]( - config).check_return_status() + ccc_site.verify_diff_state_apply[state](config).check_return_status() ccc_site.update_site_messages().check_return_status() - module.exit_json(**ccc_site.result)