Skip to content

Commit

Permalink
[change] Respect disabled organizations #552
Browse files Browse the repository at this point in the history
Closes #552
  • Loading branch information
pandafy authored Nov 28, 2023
1 parent 19163bf commit 139e936
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 5 deletions.
5 changes: 5 additions & 0 deletions openwisp_monitoring/check/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ def perform_check(self, store=True):
"""
initiates check instance and calls its check method
"""
if (
hasattr(self.content_object, 'organization_id')
and self.content_object.organization.is_active is False
):
return
return self.check_instance.check(store=True)

def perform_check_delayed(self, duration=0):
Expand Down
10 changes: 10 additions & 0 deletions openwisp_monitoring/check/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,16 @@ def test_device_unknown_no_config_check(self):
self.assertEqual(Notification.objects.count(), 0)
self.assertIsNone(c2.perform_check())

def test_device_organization_disabled_check_not_performed(self):
self._create_config(
status='modified', organization=self._create_org(is_active=False)
)
self.assertEqual(Check.objects.count(), 3)
check = Check.objects.filter(check_type=self._CONFIG_APPLIED).first()
with patch(f'{self._CONFIG_APPLIED}.check') as mocked_check:
check.perform_check()
mocked_check.assert_not_called()

def test_config_check_problem_with_interval(self):
self._create_admin()
d = self._create_device(organization=self._create_org())
Expand Down
2 changes: 1 addition & 1 deletion openwisp_monitoring/device/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def get_inlines(self, request, obj=None):
for inline in inlines:
if not hasattr(inline, 'sortable_options'):
inline.sortable_options = {'disabled': True}
if not obj or obj._state.adding:
if not obj or obj._state.adding or obj.organization.is_active is False:
inlines.remove(CheckInline)
inlines.remove(MetricInline)
return inlines
Expand Down
12 changes: 8 additions & 4 deletions openwisp_monitoring/device/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,14 @@ class DeviceMetricView(
"""

model = DeviceData
queryset = DeviceData.objects.only(
'id',
'key',
).all()
queryset = (
DeviceData.objects.filter(organization__is_active=True)
.only(
'id',
'key',
)
.all()
)
serializer_class = serializers.Serializer
permission_classes = [DevicePermission]
schema = schema
Expand Down
13 changes: 13 additions & 0 deletions openwisp_monitoring/device/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def connect_device_signals(self):
DeviceLocation = load_model('geo', 'DeviceLocation')
Metric = load_model('monitoring', 'Metric')
Chart = load_model('monitoring', 'Chart')
Organization = load_model('openwisp_users', 'Organization')

post_save.connect(
self.device_post_save_receiver,
Expand Down Expand Up @@ -120,6 +121,11 @@ def connect_device_signals(self):
sender=DeviceLocation,
dispatch_uid='post_delete_devicelocation_invalidate_devicedata_cache',
)
post_save.connect(
self.organization_post_save_receiver,
sender=Organization,
dispatch_uid='post_save_organization_disabled_monitoring',
)

@classmethod
def device_post_save_receiver(cls, instance, created, **kwargs):
Expand All @@ -134,6 +140,13 @@ def device_post_delete_receiver(cls, instance, **kwargs):
instance.checks.all().delete()
instance.metrics.all().delete()

@classmethod
def organization_post_save_receiver(cls, instance, *args, **kwargs):
if instance.is_active is False:
from .tasks import handle_disabled_organization

handle_disabled_organization.delay(str(instance.id))

def device_recovery_detection(self):
if not app_settings.DEVICE_RECOVERY_DETECTION:
return
Expand Down
19 changes: 19 additions & 0 deletions openwisp_monitoring/device/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,25 @@ def is_metric_critical(metric):
return True
return False

@classmethod
def handle_disabled_organization(cls, organization_id):
"""
Clears the management IP of all devices belonging to a
disabled organization and set their monitoring status to 'unknown'.
Parameters:
organization_id (int): The ID of the disabled organization.
Returns:
None
"""
load_model('config', 'Device').objects.filter(
organization_id=organization_id
).update(management_ip='')
cls.objects.filter(device__organization_id=organization_id).update(
status='unknown'
)


class AbstractWifiClient(TimeStampedEditableModel):
id = None
Expand Down
6 changes: 6 additions & 0 deletions openwisp_monitoring/device/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,9 @@ def write_device_metrics(pk, data, time=None, current=False):
except DeviceData.DoesNotExist:
return
device_data.writer.write(data, time, current)


@shared_task(base=OpenwispCeleryTask)
def handle_disabled_organization(organization_id):
DeviceMonitoring = load_model('device_monitoring', 'DeviceMonitoring')
DeviceMonitoring.handle_disabled_organization(organization_id)
19 changes: 19 additions & 0 deletions openwisp_monitoring/device/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,25 @@ def test_device_add_view(self):
self.assertContains(r, '<h2>Map</h2>')
self.assertContains(r, '<h2>Credentials</h2>')

def test_device_disabled_organization_admin(self):
self.create_test_data()
device = Device.objects.first()
Check.objects.create(
name='Ping check',
check_type=CHECK_CLASSES[0][0],
content_object=device,
params={},
)
org = device.organization
org.is_active = False
org.save()
url = reverse('admin:config_device_change', args=[device.pk])
response = self.client.get(url)
self.assertContains(response, '<h2>Status</h2>')
self.assertContains(response, '<h2>Charts</h2>')
self.assertNotContains(response, '<h2>Checks</h2>')
self.assertNotContains(response, '<h2>AlertSettings</h2>')

def test_remove_invalid_interface(self):
d = self._create_device(organization=self._create_org())
dd = DeviceData(name='test-device', pk=d.pk)
Expand Down
9 changes: 9 additions & 0 deletions openwisp_monitoring/device/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,15 @@ def test_200_no_date_supplied(self):
r = self.client.post(url, netjson, content_type='application/json')
self.assertEqual(r.status_code, 200)

def test_404_disabled_organization(self):
org = self._create_org(is_active=False)
device = self._create_device(organization=org)
with self.assertNumQueries(2):
response = self._post_data(device.id, device.key, self._data())
self.assertEqual(response.status_code, 404)
self.assertEqual(self.metric_queryset.count(), 0)
self.assertEqual(self.chart_queryset.count(), 0)

def test_garbage_wireless_clients(self):
o = self._create_org()
d = self._create_device(organization=o)
Expand Down
14 changes: 14 additions & 0 deletions openwisp_monitoring/device/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,20 @@ def test_deleting_device_deletes_tsdb(self):
self.assertEqual(self._read_metric(ping1), [])
self.assertNotEqual(self._read_metric(ping2), [])

def test_handle_disabled_organization(self):
device_monitoring, _, _, _ = self._create_env()
device = device_monitoring.device
device.management_ip = '10.10.0.5'
device.save()
self.assertEqual(device_monitoring.status, 'ok')
org = device.organization
org.is_active = False
org.save(update_fields=['is_active'])
device_monitoring.refresh_from_db()
device.refresh_from_db()
self.assertEqual(device_monitoring.status, 'unknown')
self.assertEqual(device.management_ip, None)


class TestWifiClientSession(TestWifiClientSessionMixin, TestCase):
wifi_client_model = WifiClient
Expand Down

0 comments on commit 139e936

Please sign in to comment.