Skip to content

Commit

Permalink
[feature] Implement Iperf check #385
Browse files Browse the repository at this point in the history
- Added initial code for Iperf check class.
- Added tests.

Closes #385
  • Loading branch information
Aryamanz29 committed Jun 14, 2022
1 parent bee496a commit 4a83003
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 13 deletions.
8 changes: 8 additions & 0 deletions openwisp_monitoring/check/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ def _connect_signals(self):
sender=load_model('config', 'Device'),
dispatch_uid='auto_config_check',
)
if app_settings.AUTO_IPERF:
from .base.models import auto_iperf_check_receiver

post_save.connect(
auto_iperf_check_receiver,
sender=load_model('config', 'Device'),
dispatch_uid='auto_iperf_check',
)
24 changes: 23 additions & 1 deletion openwisp_monitoring/check/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
from jsonfield import JSONField

from openwisp_monitoring.check import settings as app_settings
from openwisp_monitoring.check.tasks import auto_create_config_check, auto_create_ping
from openwisp_monitoring.check.tasks import (
auto_create_config_check,
auto_create_iperf_check,
auto_create_ping,
)
from openwisp_utils.base import TimeStampedEditableModel

from ...utils import transaction_on_commit
Expand Down Expand Up @@ -116,3 +120,21 @@ def auto_config_check_receiver(sender, instance, created, **kwargs):
object_id=str(instance.pk),
)
)


def auto_iperf_check_receiver(sender, instance, created, **kwargs):
"""
Implements OPENWISP_MONITORING_AUTO_IPERF
The creation step is executed in the background
"""
# we need to skip this otherwise this task will be executed
# every time the configuration is requested via checksum
if not created:
return
transaction_on_commit(
lambda: auto_create_iperf_check.delay(
model=sender.__name__.lower(),
app_label=sender._meta.app_label,
object_id=str(instance.pk),
)
)
1 change: 1 addition & 0 deletions openwisp_monitoring/check/classes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .config_applied import ConfigApplied # noqa
from .iperf import Iperf # noqa
from .ping import Ping # noqa
49 changes: 49 additions & 0 deletions openwisp_monitoring/check/classes/iperf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from swapper import load_model

from .base import BaseCheck

Chart = load_model('monitoring', 'Chart')
Metric = load_model('monitoring', 'Metric')
Device = load_model('config', 'Device')
DeviceData = load_model('device_monitoring', 'DeviceData')
Credentials = load_model('connection', 'Credentials')
AlertSettings = load_model('monitoring', 'AlertSettings')
DeviceConnection = load_model('connection', 'DeviceConnection')


class Iperf(BaseCheck):
def check(self, store=True):
pass

def store_result(self, result):
"""
store result in the DB
"""
pass

def _get_iperf_servers(self):
"""
Get iperf test servers
"""
pass

def _get_iperf_result(self, mode=None):
"""
Get iperf test result
"""
pass

def _get_metric(self):
"""
Gets or creates metric
"""
pass

def _create_charts(self, metric):
"""
Creates iperf related charts (Bandwith/Jitter)
"""
pass

def _create_alert_settings(self, metric):
pass
11 changes: 11 additions & 0 deletions openwisp_monitoring/check/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,20 @@
(
('openwisp_monitoring.check.classes.Ping', 'Ping'),
('openwisp_monitoring.check.classes.ConfigApplied', 'Configuration Applied'),
('openwisp_monitoring.check.classes.Iperf', 'Iperf'),
),
)
AUTO_PING = get_settings_value('AUTO_PING', True)
AUTO_CONFIG_CHECK = get_settings_value('AUTO_DEVICE_CONFIG_CHECK', True)
MANAGEMENT_IP_ONLY = get_settings_value('MANAGEMENT_IP_ONLY', True)
PING_CHECK_CONFIG = get_settings_value('PING_CHECK_CONFIG', {})
# By default it should be disabled.
AUTO_IPERF = get_settings_value('AUTO_IPERF', False)
# IPERF_SERVERS = get_settings_value(
# 'IPERF_SERVERS',
# {
# # Running on my local
# 'be63c4e5-a68a-4650-bfe8-733837edb8be': ['172.19.0.1'],
# # '<org-pk>': ['<ORG_IPERF_SERVER>']
# },
# )
27 changes: 27 additions & 0 deletions openwisp_monitoring/check/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,30 @@ def auto_create_config_check(
)
check.full_clean()
check.save()


@shared_task
def auto_create_iperf_check(
model, app_label, object_id, check_model=None, content_type_model=None
):
"""
Called by openwisp_monitoring.check.models.auto_iperf_check_receiver
"""
Check = check_model or get_check_model()
iperf_check_path = 'openwisp_monitoring.check.classes.Iperf'
has_check = Check.objects.filter(
object_id=object_id, content_type__model='device', check_type=iperf_check_path
).exists()
# create new check only if necessary
if has_check:
return
content_type_model = content_type_model or ContentType
ct = content_type_model.objects.get(app_label=app_label, model=model)
check = Check(
name='Iperf',
check_type=iperf_check_path,
content_type=ct,
object_id=object_id,
)
check.full_clean()
check.save()
50 changes: 39 additions & 11 deletions openwisp_monitoring/check/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

from ...device.tests import TestDeviceMonitoringMixin
from .. import settings as app_settings
from ..classes import ConfigApplied, Ping
from ..tasks import auto_create_config_check, auto_create_ping
from ..classes import ConfigApplied, Iperf, Ping
from ..tasks import auto_create_config_check, auto_create_iperf_check, auto_create_ping

Check = load_model('check', 'Check')
Metric = load_model('monitoring', 'Metric')
Expand All @@ -22,6 +22,7 @@
class TestModels(TestDeviceMonitoringMixin, TransactionTestCase):
_PING = app_settings.CHECK_CLASSES[0][0]
_CONFIG_APPLIED = app_settings.CHECK_CLASSES[1][0]
_IPERF = app_settings.CHECK_CLASSES[2][0]

def test_check_str(self):
c = Check(name='Test check')
Expand All @@ -48,6 +49,12 @@ def test_check_class(self):
check_type=self._CONFIG_APPLIED,
)
self.assertEqual(c.check_class, ConfigApplied)
with self.subTest('Test Iperf check Class'):
c = Check(
name='Iperf class check',
check_type=self._IPERF,
)
self.assertEqual(c.check_class, Iperf)

def test_base_check_class(self):
path = 'openwisp_monitoring.check.classes.base.BaseCheck'
Expand Down Expand Up @@ -82,6 +89,18 @@ def test_check_instance(self):
self.assertEqual(i.related_object, obj)
self.assertEqual(i.params, c.params)

with self.subTest('Test Iperf check instance'):
c = Check(
name='Iperf class check',
check_type=self._IPERF,
content_object=obj,
params={},
)
i = c.check_instance
self.assertIsInstance(i, Iperf)
self.assertEqual(i.related_object, obj)
self.assertEqual(i.params, c.params)

def test_validation(self):
with self.subTest('Test Ping check validation'):
check = Check(name='Ping check', check_type=self._PING, params={})
Expand All @@ -105,7 +124,7 @@ def test_validation(self):
def test_auto_check_creation(self):
self.assertEqual(Check.objects.count(), 0)
d = self._create_device(organization=self._create_org())
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
with self.subTest('Test AUTO_PING'):
c1 = Check.objects.filter(check_type=self._PING).first()
self.assertEqual(c1.content_object, d)
Expand All @@ -114,11 +133,15 @@ def test_auto_check_creation(self):
c2 = Check.objects.filter(check_type=self._CONFIG_APPLIED).first()
self.assertEqual(c2.content_object, d)
self.assertEqual(self._CONFIG_APPLIED, c2.check_type)
with self.subTest('Test AUTO_IPERF'):
c3 = Check.objects.filter(check_type=self._IPERF).first()
self.assertEqual(c3.content_object, d)
self.assertEqual(self._IPERF, c3.check_type)

def test_device_deleted(self):
self.assertEqual(Check.objects.count(), 0)
d = self._create_device(organization=self._create_org())
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
d.delete()
self.assertEqual(Check.objects.count(), 0)

Expand All @@ -129,7 +152,7 @@ def test_config_modified_device_problem(self):
self._create_config(status='modified', organization=self._create_org())
d = Device.objects.first()
d.monitoring.update_status('ok')
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
self.assertEqual(Metric.objects.count(), 0)
self.assertEqual(AlertSettings.objects.count(), 0)
check = Check.objects.filter(check_type=self._CONFIG_APPLIED).first()
Expand Down Expand Up @@ -159,7 +182,7 @@ def test_config_error(self):
self._create_config(status='error', organization=self._create_org())
dm = Device.objects.first().monitoring
dm.update_status('ok')
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
self.assertEqual(Metric.objects.count(), 0)
self.assertEqual(AlertSettings.objects.count(), 0)
check = Check.objects.filter(check_type=self._CONFIG_APPLIED).first()
Expand Down Expand Up @@ -192,7 +215,7 @@ def test_config_error(self):
@patch('openwisp_monitoring.check.settings.AUTO_PING', False)
def test_config_check_critical_metric(self):
self._create_config(status='modified', organization=self._create_org())
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
d = Device.objects.first()
dm = d.monitoring
dm.update_status('ok')
Expand All @@ -211,7 +234,7 @@ def test_config_check_critical_metric(self):

def test_no_duplicate_check_created(self):
self._create_config(organization=self._create_org())
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
d = Device.objects.first()
auto_create_config_check.delay(
model=Device.__name__.lower(),
Expand All @@ -223,13 +246,18 @@ def test_no_duplicate_check_created(self):
app_label=Device._meta.app_label,
object_id=str(d.pk),
)
self.assertEqual(Check.objects.count(), 2)
auto_create_iperf_check.delay(
model=Device.__name__.lower(),
app_label=Device._meta.app_label,
object_id=str(d.pk),
)
self.assertEqual(Check.objects.count(), 3)

def test_device_unreachable_no_config_check(self):
self._create_config(status='modified', organization=self._create_org())
d = self.device_model.objects.first()
d.monitoring.update_status('critical')
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
c2 = Check.objects.filter(check_type=self._CONFIG_APPLIED).first()
c2.perform_check()
self.assertEqual(Metric.objects.count(), 0)
Expand All @@ -240,7 +268,7 @@ def test_device_unknown_no_config_check(self):
self._create_config(status='modified', organization=self._create_org())
d = self.device_model.objects.first()
d.monitoring.update_status('unknown')
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
c2 = Check.objects.filter(check_type=self._CONFIG_APPLIED).first()
c2.perform_check()
self.assertEqual(Metric.objects.count(), 0)
Expand Down
2 changes: 1 addition & 1 deletion openwisp_monitoring/check/tests/test_ping.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def test_store_result(self, mocked_method):
device.management_ip = '10.40.0.1'
device.save()
# check created automatically by autoping
self.assertEqual(Check.objects.count(), 2)
self.assertEqual(Check.objects.count(), 3)
self.assertEqual(Metric.objects.count(), 0)
self.assertEqual(Chart.objects.count(), 0)
self.assertEqual(AlertSettings.objects.count(), 0)
Expand Down
2 changes: 2 additions & 0 deletions openwisp_monitoring/device/tests/test_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def test_trigger_device_recovery_task_regression(
dm = self._create_device_monitoring()
dm.device.management_ip = None
dm.device.save()
# Delete iperf check to prevent unnecessary response timeout
Check.objects.filter(check_type__endswith='Iperf').delete()
trigger_device_checks.delay(dm.device.pk)
self.assertTrue(Check.objects.exists())
# we expect update_status() to be called once (by the check)
Expand Down
2 changes: 2 additions & 0 deletions openwisp_monitoring/tests/test_selenium.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ def test_restoring_deleted_device(self):
org = self._get_org()
self._create_credentials(auto_add=True, organization=org)
device = self._create_config(organization=org).device
# Delete iperf check to prevent unnecessary response timeout
Check.objects.filter(check_type__endswith='Iperf').delete()
device_data = DeviceData.objects.get(id=device.id)
device_checks = device_data.checks.all()
for check in device_checks:
Expand Down
2 changes: 2 additions & 0 deletions tests/openwisp2/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@
OPENWISP_MONITORING_MAC_VENDOR_DETECTION = False
OPENWISP_MONITORING_API_URLCONF = 'openwisp_monitoring.urls'
OPENWISP_MONITORING_API_BASEURL = 'http://testserver'
# for testing AUTO_IPERF
OPENWISP_MONITORING_AUTO_IPERF = True

# Temporarily added to identify slow tests
TEST_RUNNER = 'openwisp_utils.tests.TimeLoggingTestRunner'
Expand Down

0 comments on commit 4a83003

Please sign in to comment.