diff --git a/plugins/modules/network_settings_playbook_config_generator.py b/plugins/modules/network_settings_playbook_config_generator.py index e039142df0..ebb859d22f 100644 --- a/plugins/modules/network_settings_playbook_config_generator.py +++ b/plugins/modules/network_settings_playbook_config_generator.py @@ -9541,13 +9541,11 @@ def yaml_config_generator(self, yaml_config_generator): if not module_supported_network_elements: error_msg = "No network elements defined in module schema, cannot process any components" self.log(error_msg, "CRITICAL") - self.msg = { - "message": "YAML config generation failed for module '{0}' - module schema is invalid.".format( - self.module_name - ), - "error": error_msg - } - self.set_operation_result("failed", False, self.msg, "CRITICAL") + self.msg = "YAML config generation failed for module '{0}' - module schema is invalid.".format( + self.module_name + ) + additional_info = {"error": error_msg} + self.set_operation_result("failed", False, self.msg, "CRITICAL", additional_info) return self self.log( @@ -9634,9 +9632,13 @@ def yaml_config_generator(self, yaml_config_generator): if not components_list: error_msg = "No valid components to process after filtering" self.log(error_msg, "ERROR") - self.msg = { - "message": "No configurations or components to process for module '{0}'. " - "Verify input filters or configuration.".format(self.module_name), + self.msg = ( + "No configurations or components to process for module '{0}'. " + "Verify input filters or configuration.".format(self.module_name) + ) + additional_info = { + "status": "ok", + "message": self.msg, "operation_summary": { "total_sites_processed": 0, "total_components_processed": 0, @@ -9644,7 +9646,7 @@ def yaml_config_generator(self, yaml_config_generator): "total_failed_operations": 0 } } - self.set_operation_result("ok", False, self.msg, "INFO") + self.set_operation_result("ok", False, self.msg, "INFO", additional_info) return self # Reset operation tracking for clean state @@ -9935,12 +9937,16 @@ def yaml_config_generator(self, yaml_config_generator): "WARNING" ) - self.msg = { - "message": "No configurations or components to process for module '{0}'. " - "Verify input filters or configuration.".format(self.module_name), + self.msg = ( + "No configurations or components to process for module '{0}'. " + "Verify input filters or configuration.".format(self.module_name) + ) + additional_info = { + "status": "ok", + "message": self.msg, "operation_summary": slim_operation_summary } - self.set_operation_result("ok", False, self.msg, "INFO") + self.set_operation_result("ok", False, self.msg, "INFO", additional_info) return self # Create final YAML structure @@ -9955,11 +9961,16 @@ def yaml_config_generator(self, yaml_config_generator): final_dict["config"] = final_list if not final_list: - self.msg = { - "message": "No configurations or components to process for module '{0}'. Verify input filters or configuration.".format(self.module_name), + self.msg = ( + "No configurations or components to process for module '{0}'. " + "Verify input filters or configuration.".format(self.module_name) + ) + additional_info = { + "status": "ok", + "message": self.msg, "operation_summary": slim_operation_summary } - self.set_operation_result("ok", False, self.msg, "INFO") + self.set_operation_result("ok", False, self.msg, "INFO", additional_info) return self # Write to YAML file @@ -9995,39 +10006,39 @@ def yaml_config_generator(self, yaml_config_generator): "INFO" ) - self.msg = { - "message": "YAML config generation succeeded for module '{0}'.".format( - self.module_name - ), + self.msg = "YAML config generation succeeded for module '{0}'.".format( + self.module_name + ) + additional_info = { + "status": "success", + "message": self.msg, "file_path": file_path, "configurations_generated": len(final_list), "operation_summary": slim_operation_summary } - self.set_operation_result("success", True, self.msg, "INFO") + self.set_operation_result("success", True, self.msg, "INFO", additional_info) else: - error_msg = "Failed to write YAML configuration to file: {0}".format(file_path) - self.log(error_msg, "ERROR") - - # Exit log with failure summary + # write_dict_to_yaml returns False when the existing file content is + # identical to the newly generated content (idempotent - no write needed). + # This is not a failure; the file is already up-to-date. self.log( - "YAML playbook configuration generation workflow failed for module '{0}'. " - "Processed {1} component(s) successfully but unable to write output file: {2}".format( - self.module_name, - consolidated_operation_summary["total_components_processed"], - file_path - ), - "ERROR" + "YAML configuration file '{0}' content is identical to newly generated " + "content. Skipping write (idempotent).".format(file_path), + "INFO" ) - self.msg = { - "message": "YAML config generation failed for module '{0}' - unable to write to file.".format( - self.module_name - ), + self.msg = ( + "YAML configuration file already up-to-date for module '{0}'. " + "No changes written.".format(self.module_name) + ) + additional_info = { + "status": "ok", + "message": self.msg, "file_path": file_path, - "error": error_msg, + "configurations_generated": len(final_list), "operation_summary": slim_operation_summary } - self.set_operation_result("failed", True, self.msg, "ERROR") + self.set_operation_result("ok", False, self.msg, "INFO", additional_info) return self diff --git a/tests/unit/modules/dnac/fixtures/network_settings_playbook_config_generation.json b/tests/unit/modules/dnac/fixtures/network_settings_playbook_config_generation.json index fa780d70b7..fbd3238b37 100644 --- a/tests/unit/modules/dnac/fixtures/network_settings_playbook_config_generation.json +++ b/tests/unit/modules/dnac/fixtures/network_settings_playbook_config_generation.json @@ -47,10 +47,10 @@ "components_list": ["reserve_pool_details"], "reserve_pool_details": [ { - "pool_name": "Reserve_Pool_1" + "site_name": "Global/India/Mumbai" }, { - "pool_name": "Reserve_Pool_2" + "site_name": "Global/India/Delhi" } ] } @@ -61,10 +61,10 @@ "components_list": ["network_management_details"], "network_management_details": [ { - "site_name": "Global/India/Mumbai" + "site_name_list": ["Global/India/Mumbai"] }, { - "site_name": "Global/India/Delhi" + "site_name_list": ["Global/India/Delhi"] } ] } @@ -72,15 +72,7 @@ "playbook_config_device_controllability_by_site": { "component_specific_filters": { - "components_list": ["device_controllability_details"], - "device_controllability_details": [ - { - "site_name": "Global/India/Mumbai" - }, - { - "site_name": "Global/India/Delhi" - } - ] + "components_list": ["device_controllability_details"] } }, diff --git a/tests/unit/modules/dnac/test_network_settings_playbook_config_generator.py b/tests/unit/modules/dnac/test_network_settings_playbook_config_generator.py index 3281a17b51..fedc396d5a 100644 --- a/tests/unit/modules/dnac/test_network_settings_playbook_config_generator.py +++ b/tests/unit/modules/dnac/test_network_settings_playbook_config_generator.py @@ -108,7 +108,7 @@ def load_fixtures(self, response=None, device=""): elif "reserve_pools_by_pool_name" in self._testMethodName: self.run_dnac_exec.side_effect = [ - self.test_data.get("get_reserve_ip_pool_details"), + self.test_data.get("get_site_details"), self.test_data.get("get_reserve_ip_pool_details"), ] @@ -121,8 +121,6 @@ def load_fixtures(self, response=None, device=""): elif "device_controllability_by_site" in self._testMethodName: self.run_dnac_exec.side_effect = [ - self.test_data.get("get_site_details"), - self.test_data.get("get_device_controllability_response"), self.test_data.get("get_device_controllability_response"), ]