Skip to content

Commit

Permalink
[change] Notify users of background subnet division rule errors #837
Browse files Browse the repository at this point in the history
Closes #837
  • Loading branch information
pandafy committed May 30, 2024
1 parent c4a1683 commit 35b43a6
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ jobs:
- name: Install openwisp-controller
run: |
pip install -U -e .
# TODO: Remove before merging
pip install -IU --no-deps "openwisp-notifications @ https://github.com/openwisp/openwisp-notifications/tarball/master"
pip install ${{ matrix.django-version }}
- name: QA checks
Expand Down
18 changes: 17 additions & 1 deletion openwisp_controller/subnet_division/rule_types/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.dispatch import Signal
from django.utils.translation import gettext_lazy as _
from netaddr import IPNetwork
from openwisp_notifications.signals import notify
from swapper import load_model

from ..signals import subnet_provisioned
Expand Down Expand Up @@ -205,7 +206,22 @@ def create_subnets(config, division_rule, max_subnet, generated_indexes):

for subnet_id in range(1, division_rule.number_of_subnets + 1):
if not ip_network(str(required_subnet)).subnet_of(master_subnet.subnet):
logger.error(f'Cannot create more subnets of {master_subnet}')
notify.send(
sender=config,
type='generic_message',
target=config.device,
action_object=master_subnet,
level='error',
message=(
'Failed to provision subnets for'
' [{notification.target}]({notification.target_link})'
),
description=(
'The [{notification.action_object}]({notification.action_link})'
' subnet has run out of space.'
),
)
logger.info(f'Cannot create more subnets of {master_subnet}')
break
subnet_obj = Subnet(
name=f'{division_rule.label}_subnet{subnet_id}',
Expand Down
38 changes: 37 additions & 1 deletion openwisp_controller/subnet_division/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@
VpnClient = load_model('config', 'VpnClient')
Device = load_model('config', 'Device')
OrganizationConfigSettings = load_model('config', 'OrganizationConfigSettings')
Notification = load_model('openwisp_notifications', 'Notification')


class BaseSubnetDivisionRule:
config_label = 'config'
ipam_label = 'openwisp_ipam'

@property
def ip_query(self):
return IpAddress.objects.exclude(id=self.vpn_server.ip_id)
Expand Down Expand Up @@ -415,7 +419,7 @@ def test_multiple_vpnclient_delete(self):
ip_query.count(), (rule.number_of_subnets * rule.number_of_ips)
)

@patch('logging.Logger.error')
@patch('logging.Logger.info')
def test_subnets_exhausted(self, mocked_logger):
subnet = self._get_master_subnet(
'10.0.0.0/28', master_subnet=self.master_subnet
Expand All @@ -424,6 +428,8 @@ def test_subnets_exhausted(self, mocked_logger):
master_subnet=subnet,
size=29,
)
# A user is required to verify notification is created
self._get_admin()
self.vpn_server.subnet = subnet
self.vpn_server.save()
self.config.templates.add(self.template)
Expand All @@ -433,6 +439,36 @@ def test_subnets_exhausted(self, mocked_logger):
)
config2.templates.add(self.template)
mocked_logger.assert_called_with(f'Cannot create more subnets of {subnet}')
notification = Notification.objects.first()
self.assertEqual(notification.level, 'error')
self.assertEqual(notification.type, 'generic_message')
self.assertEqual(notification.target, config2.device)
self.assertEqual(notification.action_object, subnet)
self.assertEqual(
notification.message,
(
'<p>Failed to provision subnets for '
'<a href="https://example.com{device_path}">'
'{device_name}</a></p>'
).format(
device_path=reverse(
f'admin:{self.config_label}_device_change', args=[config2.device_id]
),
device_name=config2.device.name,
),
)
self.assertEqual(
notification.rendered_description,
(
'<p>The <a href="https://example.com{subnet_path}">'
'{subnet_name}</a> subnet has run out of space.</p>'
).format(
subnet_path=reverse(
f'admin:{self.ipam_label}_subnet_change', args=[subnet.id]
),
subnet_name=subnet,
),
)

def test_vpn_subnet_none(self):
self.vpn_server.subnet = None
Expand Down
2 changes: 1 addition & 1 deletion tests/openwisp2/sample_subnet_division/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TestSubnetAdmin(BaseTestSubnetAdmin):


class TestSubnetDivsionRule(BaseTestSubnetDivisionRule):
pass
config_label = 'sample_config'


class TestIPAdmin(BaseTestIPAdmin):
Expand Down

0 comments on commit 35b43a6

Please sign in to comment.