From 2fbaaaf20f0a718e9432a82fbb8b159936b2175a Mon Sep 17 00:00:00 2001 From: Gagan Deep Date: Mon, 2 Dec 2024 22:46:49 +0530 Subject: [PATCH 1/4] [qa] Formatted README.rst --- README.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index cddb102a0..c899f0d8c 100644 --- a/README.rst +++ b/README.rst @@ -53,8 +53,8 @@ Other popular building blocks that are part of the OpenWISP ecosystem are: provides device status monitoring, collection of metrics, charts, alerts, possibility to define custom checks - `openwisp-firmware-upgrader - `_: automated firmware - upgrades (single devices or mass network upgrades) + `_: automated + firmware upgrades (single devices or mass network upgrades) - `openwisp-radius `_: based on FreeRADIUS, allows to implement network access authentication systems like 802.1x WPA2 Enterprise, captive portal authentication, @@ -65,10 +65,11 @@ Other popular building blocks that are part of the OpenWISP ecosystem are: daemons or other network software (e.g.: OpenVPN); it can be used in conjunction with openwisp-monitoring to get a better idea of the state of the network -- `openwisp-ipam `_: allows to manage - the assignment of IP addresses used in the network -- `openwisp-notifications `_: - allows users to be aware of important events happening in the network. +- `openwisp-ipam `_: allows to + manage the assignment of IP addresses used in the network +- `openwisp-notifications + `_: allows users to be + aware of important events happening in the network. **For a more complete overview of the OpenWISP modules and architecture**, see the `OpenWISP Architecture Overview From 1995574ede8b6c8729c4d6b21279ac23f1fd0b5f Mon Sep 17 00:00:00 2001 From: Gagan Deep Date: Mon, 2 Dec 2024 22:47:38 +0530 Subject: [PATCH 2/4] [deps] Bumped version to 1.2.0a --- openwisp_controller/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openwisp_controller/__init__.py b/openwisp_controller/__init__.py index 6e2bfeb2a..d35f51f21 100644 --- a/openwisp_controller/__init__.py +++ b/openwisp_controller/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 1, 0, 'final') +VERSION = (1, 2, 0, 'alpha') __version__ = VERSION # alias From bd3d11a5b1e8ff62d0bbd42aef8e4a86c8015423 Mon Sep 17 00:00:00 2001 From: Gagan Deep Date: Mon, 2 Dec 2024 22:06:52 +0530 Subject: [PATCH 3/4] [fix] Allow updating templates with invalid configurations Previously, fixing an invalid template configuration via the UI was blocked due to the cache invalidation mechanism. This mechanism attempted to evaluate the existing configuration, triggering a ValidationError and preventing updates. --- openwisp_controller/config/base/template.py | 10 +++++++++- .../config/tests/test_template.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/openwisp_controller/config/base/template.py b/openwisp_controller/config/base/template.py index 1ac764882..25c6a7d00 100644 --- a/openwisp_controller/config/base/template.py +++ b/openwisp_controller/config/base/template.py @@ -6,6 +6,7 @@ from django.db import models, transaction from django.utils.translation import gettext_lazy as _ from jsonfield import JSONField +from netjsonconfig.exceptions import ValidationError as NetjsonconfigValidationError from swapper import get_model_name from taggit.managers import TaggableManager @@ -115,7 +116,14 @@ def save(self, *args, **kwargs): if hasattr(self, 'backend_instance'): del self.backend_instance current = self.__class__.objects.get(pk=self.pk) - update_related_config_status = self.checksum != current.checksum + try: + current_checksum = current.checksum + except NetjsonconfigValidationError: + # If the Netjsonconfig library upgrade changes the schema, + # the old configuration may become invalid, raising an exception. + # Setting the checksum to None forces related configurations to update. + current_checksum = None + update_related_config_status = self.checksum != current_checksum # save current changes super().save(*args, **kwargs) # update relations diff --git a/openwisp_controller/config/tests/test_template.py b/openwisp_controller/config/tests/test_template.py index 914499e7f..1db5410d0 100644 --- a/openwisp_controller/config/tests/test_template.py +++ b/openwisp_controller/config/tests/test_template.py @@ -7,6 +7,7 @@ from django.db import transaction from django.test import TestCase, TransactionTestCase from netjsonconfig import OpenWrt +from netjsonconfig.exceptions import ValidationError as NetjsonconfigValidationError from swapper import load_model from openwisp_utils.tests import catch_signal @@ -733,3 +734,18 @@ def test_task_timeout(self, mocked_update_related_config_status): template.save() mocked_error.assert_called_once() mocked_update_related_config_status.assert_called_once() + + def test_fixing_wrong_configuration(self): + template = self._create_template() + # create a wrong configuration + Template.objects.update(config={'interfaces': [{'name': 'eth0', 'type': ''}]}) + # Ensure the configuration raises ValidationError + with self.assertRaises(NetjsonconfigValidationError): + template.refresh_from_db() + del template.backend_instance + template.checksum + + del template.backend_instance + template.config = {'interfaces': [{'name': 'eth0', 'type': 'ethernet'}]} + template.full_clean() + template.save() From 455144437b947fa343e39e0cea33ca997782f369 Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Tue, 3 Dec 2024 18:04:56 -0300 Subject: [PATCH 4/4] [chores] Moved and renamed test for #948 Related to #948 --- .../config/tests/test_template.py | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/openwisp_controller/config/tests/test_template.py b/openwisp_controller/config/tests/test_template.py index 1db5410d0..53540c6ea 100644 --- a/openwisp_controller/config/tests/test_template.py +++ b/openwisp_controller/config/tests/test_template.py @@ -501,6 +501,20 @@ def test_required_vpn_template_corner_case(self): # {'__all__': ['VPN client with this Config and Vpn already exists.']} self.assertIsNotNone(vpn_client) + def test_regression_preventing_from_fixing_invalid_conf(self): + template = self._create_template() + # create a template with an invalid configuration + Template.objects.update(config={'interfaces': [{'name': 'eth0', 'type': ''}]}) + # ensure the configuration raises ValidationError + with self.assertRaises(NetjsonconfigValidationError): + template.refresh_from_db() + del template.backend_instance + template.checksum + del template.backend_instance + template.config = {'interfaces': [{'name': 'eth0', 'type': 'ethernet'}]} + template.full_clean() + template.save() + class TestTemplateTransaction( TransactionTestMixin, @@ -734,18 +748,3 @@ def test_task_timeout(self, mocked_update_related_config_status): template.save() mocked_error.assert_called_once() mocked_update_related_config_status.assert_called_once() - - def test_fixing_wrong_configuration(self): - template = self._create_template() - # create a wrong configuration - Template.objects.update(config={'interfaces': [{'name': 'eth0', 'type': ''}]}) - # Ensure the configuration raises ValidationError - with self.assertRaises(NetjsonconfigValidationError): - template.refresh_from_db() - del template.backend_instance - template.checksum - - del template.backend_instance - template.config = {'interfaces': [{'name': 'eth0', 'type': 'ethernet'}]} - template.full_clean() - template.save()