From 8e6ed07836c911c41b77da51b6f00af6a9404aad Mon Sep 17 00:00:00 2001 From: itdependsnetworks Date: Sat, 31 Aug 2024 00:36:36 -0400 Subject: [PATCH] Fixed issue where compliance amongst other fields were not being updated when Django 4.2 was installed. --- docs/admin/release_notes/version_2.1.md | 1 + nautobot_golden_config/__init__.py | 2 +- nautobot_golden_config/models.py | 7 +++ nautobot_golden_config/tests/test_models.py | 53 +++++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/docs/admin/release_notes/version_2.1.md b/docs/admin/release_notes/version_2.1.md index 91e03c7e..28b89bdf 100644 --- a/docs/admin/release_notes/version_2.1.md +++ b/docs/admin/release_notes/version_2.1.md @@ -10,6 +10,7 @@ ### Fixed - [#792](https://github.com/nautobot/nautobot-app-golden-config/issues/792) - Fixed issue with dynamic groups not being called in 2.3.0. +- [#800](https://github.com/nautobot/nautobot-app-golden-config/issues/800) - Fixed issue where compliance amongst other fields were not being updated when Django 4.2 was installed. ### Changed diff --git a/nautobot_golden_config/__init__.py b/nautobot_golden_config/__init__.py index 49585ba6..86818250 100644 --- a/nautobot_golden_config/__init__.py +++ b/nautobot_golden_config/__init__.py @@ -38,7 +38,7 @@ class GoldenConfig(NautobotAppConfig): "get_custom_compliance": None, # This is an experimental and undocumented setting that will change in the future!! # Use at your own risk!!!!! - "_manual_dynamic_group_mgmt": False, + "_manual_dynamic_group_mgmt": False, "jinja_env": { "undefined": "jinja2.StrictUndefined", "trim_blocks": True, diff --git a/nautobot_golden_config/models.py b/nautobot_golden_config/models.py index 3e31debd..16bc5ae7 100644 --- a/nautobot_golden_config/models.py +++ b/nautobot_golden_config/models.py @@ -415,6 +415,13 @@ def save(self, *args, **kwargs): self.remediation_on_save() self.full_clean() + # This accounts for django 4.2 `Setting update_fields in Model.save() may now be required` change + # in behavior + if kwargs.get("update_fields"): + kwargs["update_fields"].update( + {"compliance", "compliance_int", "ordered", "missing", "extra", "remediation"} + ) + super().save(*args, **kwargs) diff --git a/nautobot_golden_config/tests/test_models.py b/nautobot_golden_config/tests/test_models.py index 88e5f17c..90b199ba 100644 --- a/nautobot_golden_config/tests/test_models.py +++ b/nautobot_golden_config/tests/test_models.py @@ -21,6 +21,7 @@ from .conftest import ( create_config_compliance, create_device, + create_feature_rule_cli_with_remediation, create_feature_rule_json, create_feature_rule_xml, create_job_result, @@ -36,6 +37,7 @@ def setUp(self): self.device = create_device() self.compliance_rule_json = create_feature_rule_json(self.device) self.compliance_rule_xml = create_feature_rule_xml(self.device) + self.compliance_rule_cli = create_feature_rule_cli_with_remediation(self.device) def test_create_config_compliance_success_json(self): """Successful.""" @@ -119,6 +121,57 @@ def test_config_compliance_signal_change_platform(self): ) self.assertEqual(ConfigCompliance.objects.filter(device=self.device).count(), 1) + def test_update_or_create(self): + """We test this to ensure regression against + https://docs.djangoproject.com/en/5.1/releases/4.2/#setting-update-fields-in-model-save-may-now-be-required.""" + + RemediationSetting.objects.create( + platform=self.device.platform, + remediation_type=RemediationTypeChoice.TYPE_HIERCONFIG, + ) + + cc_obj, _ = ConfigCompliance.objects.update_or_create( + device=self.device, + rule=self.compliance_rule_cli, + defaults={ + "actual": "ntp 1.1.1.1\nntp 2.2.2.2", + "intended": "ntp 1.1.1.1\nntp 3.3.3.3", + }, + ) + + self.assertFalse(cc_obj.compliance) + self.assertFalse(cc_obj.compliance_int) + self.assertEqual(cc_obj.missing, "ntp 3.3.3.3") + self.assertEqual(cc_obj.extra, "ntp 2.2.2.2") + self.assertEqual(cc_obj.remediation, "no ntp 2.2.2.2\nntp 3.3.3.3") + + # We run again to ensure this works, the issue actually only shows on + # when `update_fields` is set + cc_obj_2, _ = ConfigCompliance.objects.update_or_create( + device=self.device, + rule=self.compliance_rule_cli, + defaults={ + "actual": "ntp 1.1.1.1\nntp 2.2.2.2", + "intended": "ntp 1.1.1.1\nntp 2.2.2.2", + }, + ) + + self.assertTrue(cc_obj_2.compliance) + self.assertTrue(cc_obj_2.compliance_int) + self.assertEqual(cc_obj_2.missing, "") + self.assertEqual(cc_obj_2.extra, "") + self.assertEqual(cc_obj_2.remediation, "") + + cc_obj_3 = ConfigCompliance.objects.get(device=self.device, rule=self.compliance_rule_cli) + cc_obj_3.intended = "ntp 1.1.1.1\nntp 3.3.3.3" + cc_obj_3.save() + + self.assertFalse(cc_obj.compliance) + self.assertFalse(cc_obj.compliance_int) + self.assertEqual(cc_obj.missing, "ntp 3.3.3.3") + self.assertEqual(cc_obj.extra, "ntp 2.2.2.2") + self.assertEqual(cc_obj.remediation, "no ntp 2.2.2.2\nntp 3.3.3.3") + class GoldenConfigTestCase(TestCase): """Test GoldenConfig Model."""