From c886d8a2def188337e7768469b45dd51bc7f404e Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Wed, 19 Oct 2016 12:49:14 +0200 Subject: [PATCH] Add editing for port security Now it is possible to enable/disable port security in Horizon, when the port-security extension is available. Closes-Bug: #1634877 Change-Id: I6b17b49bca8e5d1a2aff10fe613ecd70590c097b --- .../dashboards/admin/networks/ports/forms.py | 18 ++++ .../dashboards/admin/networks/ports/tests.py | 89 +++++++++++++++++-- .../project/networks/ports/forms.py | 14 +++ .../project/networks/ports/tests.py | 32 ++++++- .../project/networks/ports/views.py | 2 + .../notes/port-security-81278703eae4f927.yaml | 6 ++ 6 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/port-security-81278703eae4f927.yaml diff --git a/openstack_dashboard/dashboards/admin/networks/ports/forms.py b/openstack_dashboard/dashboards/admin/networks/ports/forms.py index 22c849571b..c7bf732138 100644 --- a/openstack_dashboard/dashboards/admin/networks/ports/forms.py +++ b/openstack_dashboard/dashboards/admin/networks/ports/forms.py @@ -80,6 +80,17 @@ class CreatePort(project_forms.CreatePort): msg = _("Unable to retrieve MAC learning state") exceptions.handle(self.request, msg) + try: + if api.neutron.is_extension_supported(request, 'port-security'): + self.fields['port_security_enabled'] = forms.BooleanField( + label=_("Port Security"), + help_text=_("Enable anti-spoofing rules for the port"), + initial=True, + required=False) + except Exception: + msg = _("Unable to retrieve port security state") + exceptions.handle(self.request, msg) + def handle(self, request, data): try: # We must specify tenant_id of the network which a subnet is @@ -108,6 +119,9 @@ class CreatePort(project_forms.CreatePort): if data.get('mac_state'): params['mac_learning_enabled'] = data['mac_state'] + if 'port_security_enabled' in data: + params['port_security_enabled'] = data['port_security_enabled'] + port = api.neutron.port_create(request, **params) msg = _('Port %s was successfully created.') % port['id'] LOG.debug(msg) @@ -152,6 +166,10 @@ class UpdatePort(project_forms.UpdatePort): if 'mac_state' in data: extension_kwargs['mac_learning_enabled'] = data['mac_state'] + if 'port_security_enabled' in data: + extension_kwargs['port_security_enabled'] = \ + data['port_security_enabled'] + port = api.neutron.port_update(request, data['port_id'], name=data['name'], diff --git a/openstack_dashboard/dashboards/admin/networks/ports/tests.py b/openstack_dashboard/dashboards/admin/networks/ports/tests.py index 73fe1f5f03..22f5d1d3f7 100644 --- a/openstack_dashboard/dashboards/admin/networks/ports/tests.py +++ b/openstack_dashboard/dashboards/admin/networks/ports/tests.py @@ -84,7 +84,13 @@ class NetworkPortTests(test.BaseAdminViewTests): def test_port_create_get_with_mac_learning(self): self._test_port_create_get(mac_learning=True) - def _test_port_create_get(self, mac_learning=False, binding=False): + @test.create_stubs({api.neutron: ('network_get', + 'is_extension_supported',)}) + def test_port_create_get_with_port_security(self): + self._test_port_create_get(port_security=True) + + def _test_port_create_get(self, mac_learning=False, binding=False, + port_security=False): network = self.networks.first() api.neutron.network_get(IsA(http.HttpRequest), network.id)\ @@ -96,6 +102,9 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'binding')\ .AndReturn(binding) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) self.mox.ReplayAll() url = reverse('horizon:admin:networks:addport', @@ -116,7 +125,14 @@ class NetworkPortTests(test.BaseAdminViewTests): def test_port_create_post_with_mac_learning(self): self._test_port_create_post(mac_learning=True, binding=False) - def _test_port_create_post(self, mac_learning=False, binding=False): + @test.create_stubs({api.neutron: ('network_get', + 'is_extension_supported', + 'port_create',)}) + def test_port_create_post_with_port_security(self): + self._test_port_create_post(port_security=True) + + def _test_port_create_post(self, mac_learning=False, binding=False, + port_security=False): network = self.networks.first() port = self.ports.first() api.neutron.network_get(IsA(http.HttpRequest), @@ -134,12 +150,17 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'binding') \ .AndReturn(binding) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) extension_kwargs = {} if binding: extension_kwargs['binding__vnic_type'] = \ port.binding__vnic_type if mac_learning: extension_kwargs['mac_learning_enabled'] = True + if port_security: + extension_kwargs['port_security_enabled'] = True api.neutron.port_create(IsA(http.HttpRequest), tenant_id=network.tenant_id, network_id=network.id, @@ -163,6 +184,8 @@ class NetworkPortTests(test.BaseAdminViewTests): form_data['binding__vnic_type'] = port.binding__vnic_type if mac_learning: form_data['mac_state'] = True + if port_security: + form_data['port_security_enabled'] = True url = reverse('horizon:admin:networks:addport', args=[port.network_id]) res = self.client.post(url, form_data) @@ -189,6 +212,9 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(True) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(True) extension_kwargs = {} extension_kwargs['binding__vnic_type'] = \ port.binding__vnic_type @@ -237,8 +263,15 @@ class NetworkPortTests(test.BaseAdminViewTests): def test_port_create_post_exception_with_mac_learning(self): self._test_port_create_post_exception(mac_learning=True) + @test.create_stubs({api.neutron: ('network_get', + 'port_create', + 'is_extension_supported',)}) + def test_port_create_post_exception_with_port_security(self): + self._test_port_create_post_exception(port_security=True) + def _test_port_create_post_exception(self, mac_learning=False, - binding=False): + binding=False, + port_security=False): network = self.networks.first() port = self.ports.first() api.neutron.network_get(IsA(http.HttpRequest), @@ -256,11 +289,16 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'binding') \ .AndReturn(binding) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) extension_kwargs = {} if binding: extension_kwargs['binding__vnic_type'] = port.binding__vnic_type if mac_learning: extension_kwargs['mac_learning_enabled'] = True + if port_security: + extension_kwargs['port_security_enabled'] = True api.neutron.port_create(IsA(http.HttpRequest), tenant_id=network.tenant_id, network_id=network.id, @@ -285,6 +323,8 @@ class NetworkPortTests(test.BaseAdminViewTests): form_data['binding__vnic_type'] = port.binding__vnic_type if mac_learning: form_data['mac_learning_enabled'] = True + if port_security: + form_data['port_security_enabled'] = True url = reverse('horizon:admin:networks:addport', args=[port.network_id]) res = self.client.post(url, form_data) @@ -303,7 +343,13 @@ class NetworkPortTests(test.BaseAdminViewTests): def test_port_update_get_with_mac_learning(self): self._test_port_update_get(mac_learning=True) - def _test_port_update_get(self, mac_learning=False, binding=False): + @test.create_stubs({api.neutron: ('port_get', + 'is_extension_supported',)}) + def test_port_update_get_with_port_security(self): + self._test_port_update_get(port_security=True) + + def _test_port_update_get(self, mac_learning=False, binding=False, + port_security=False): port = self.ports.first() api.neutron.port_get(IsA(http.HttpRequest), port.id)\ @@ -314,6 +360,9 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) self.mox.ReplayAll() url = reverse('horizon:admin:networks:editport', @@ -334,7 +383,14 @@ class NetworkPortTests(test.BaseAdminViewTests): def test_port_update_post_with_mac_learning(self): self._test_port_update_post(mac_learning=True) - def _test_port_update_post(self, mac_learning=False, binding=False): + @test.create_stubs({api.neutron: ('port_get', + 'is_extension_supported', + 'port_update')}) + def test_port_update_post_with_port_security(self): + self._test_port_update_post(port_security=True) + + def _test_port_update_post(self, mac_learning=False, binding=False, + port_security=False): port = self.ports.first() api.neutron.port_get(IsA(http.HttpRequest), port.id)\ .AndReturn(port) @@ -344,11 +400,16 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) extension_kwargs = {} if binding: extension_kwargs['binding__vnic_type'] = port.binding__vnic_type if mac_learning: extension_kwargs['mac_learning_enabled'] = True + if port_security: + extension_kwargs['port_security_enabled'] = True api.neutron.port_update(IsA(http.HttpRequest), port.id, name=port.name, admin_state_up=port.admin_state_up, @@ -371,6 +432,8 @@ class NetworkPortTests(test.BaseAdminViewTests): form_data['binding__vnic_type'] = port.binding__vnic_type if mac_learning: form_data['mac_state'] = True + if port_security: + form_data['port_security_enabled'] = True url = reverse('horizon:admin:networks:editport', args=[port.network_id, port.id]) res = self.client.post(url, form_data) @@ -390,8 +453,15 @@ class NetworkPortTests(test.BaseAdminViewTests): def test_port_update_post_exception_with_mac_learning(self): self._test_port_update_post_exception(mac_learning=True, binding=False) + @test.create_stubs({api.neutron: ('port_get', + 'is_extension_supported', + 'port_update')}) + def test_port_update_post_exception_with_port_security(self): + self._test_port_update_post_exception(port_security=True) + def _test_port_update_post_exception(self, mac_learning=False, - binding=False): + binding=False, + port_security=False): port = self.ports.first() api.neutron.port_get(IsA(http.HttpRequest), port.id)\ .AndReturn(port) @@ -401,11 +471,16 @@ class NetworkPortTests(test.BaseAdminViewTests): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) extension_kwargs = {} if binding: extension_kwargs['binding__vnic_type'] = port.binding__vnic_type if mac_learning: extension_kwargs['mac_learning_enabled'] = True + if port_security: + extension_kwargs['port_security_enabled'] = True api.neutron.port_update(IsA(http.HttpRequest), port.id, name=port.name, admin_state_up=port.admin_state_up, @@ -427,6 +502,8 @@ class NetworkPortTests(test.BaseAdminViewTests): form_data['binding__vnic_type'] = port.binding__vnic_type if mac_learning: form_data['mac_state'] = True + if port_security: + form_data['port_security_enabled'] = True url = reverse('horizon:admin:networks:editport', args=[port.network_id, port.id]) res = self.client.post(url, form_data) diff --git a/openstack_dashboard/dashboards/project/networks/ports/forms.py b/openstack_dashboard/dashboards/project/networks/ports/forms.py index 9085981c8b..05570770d0 100644 --- a/openstack_dashboard/dashboards/project/networks/ports/forms.py +++ b/openstack_dashboard/dashboards/project/networks/ports/forms.py @@ -197,6 +197,16 @@ class UpdatePort(forms.SelfHandlingForm): msg = _("Unable to retrieve MAC learning state") exceptions.handle(self.request, msg) + try: + if api.neutron.is_extension_supported(request, 'port-security'): + self.fields['port_security_enabled'] = forms.BooleanField( + label=_("Port Security"), + help_text=_("Enable anti-spoofing rules for the port"), + required=False) + except Exception: + msg = _("Unable to retrieve port security state") + exceptions.handle(self.request, msg) + def handle(self, request, data): data['admin_state'] = (data['admin_state'] == 'True') try: @@ -207,6 +217,10 @@ class UpdatePort(forms.SelfHandlingForm): data['binding__vnic_type'] if 'mac_state' in data: extension_kwargs['mac_learning_enabled'] = data['mac_state'] + if 'port_security_enabled' in data: + extension_kwargs['port_security_enabled'] = \ + data['port_security_enabled'] + port = api.neutron.port_update(request, data['port_id'], name=data['name'], diff --git a/openstack_dashboard/dashboards/project/networks/ports/tests.py b/openstack_dashboard/dashboards/project/networks/ports/tests.py index e20e4b2c34..24a9d8c10d 100644 --- a/openstack_dashboard/dashboards/project/networks/ports/tests.py +++ b/openstack_dashboard/dashboards/project/networks/ports/tests.py @@ -116,7 +116,14 @@ class NetworkPortTests(test.TestCase): def test_port_update_post_with_mac_learning(self): self._test_port_update_post(mac_learning=True) - def _test_port_update_post(self, mac_learning=False, binding=False): + @test.create_stubs({api.neutron: ('port_get', + 'is_extension_supported', + 'port_update')}) + def test_port_update_post_with_port_security(self): + self._test_port_update_post(port_security=True) + + def _test_port_update_post(self, mac_learning=False, binding=False, + port_security=False): port = self.ports.first() api.neutron.port_get(IsA(http.HttpRequest), port.id)\ .AndReturn(port) @@ -126,11 +133,16 @@ class NetworkPortTests(test.TestCase): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) extension_kwargs = {} if binding: extension_kwargs['binding__vnic_type'] = port.binding__vnic_type if mac_learning: extension_kwargs['mac_learning_enabled'] = True + if port_security: + extension_kwargs['port_security_enabled'] = True api.neutron.port_update(IsA(http.HttpRequest), port.id, name=port.name, admin_state_up=port.admin_state_up, @@ -146,6 +158,8 @@ class NetworkPortTests(test.TestCase): form_data['binding__vnic_type'] = port.binding__vnic_type if mac_learning: form_data['mac_state'] = True + if port_security: + form_data['port_security_enabled'] = True url = reverse('horizon:project:networks:editport', args=[port.network_id, port.id]) res = self.client.post(url, form_data) @@ -165,8 +179,15 @@ class NetworkPortTests(test.TestCase): def test_port_update_post_exception_with_mac_learning(self): self._test_port_update_post_exception(mac_learning=True) + @test.create_stubs({api.neutron: ('port_get', + 'is_extension_supported', + 'port_update')}) + def test_port_update_post_exception_with_port_security(self): + self._test_port_update_post_exception(port_security=True) + def _test_port_update_post_exception(self, mac_learning=False, - binding=False): + binding=False, + port_security=False): port = self.ports.first() api.neutron.port_get(IsA(http.HttpRequest), port.id)\ @@ -177,11 +198,16 @@ class NetworkPortTests(test.TestCase): api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) + api.neutron.is_extension_supported(IsA(http.HttpRequest), + 'port-security')\ + .AndReturn(port_security) extension_kwargs = {} if binding: extension_kwargs['binding__vnic_type'] = port.binding__vnic_type if mac_learning: extension_kwargs['mac_learning_enabled'] = True + if port_security: + extension_kwargs['port_security_enabled'] = True api.neutron.port_update(IsA(http.HttpRequest), port.id, name=port.name, admin_state_up=port.admin_state_up, @@ -197,6 +223,8 @@ class NetworkPortTests(test.TestCase): form_data['binding__vnic_type'] = port.binding__vnic_type if mac_learning: form_data['mac_state'] = True + if port_security: + form_data['port_security_enabled'] = True url = reverse('horizon:project:networks:editport', args=[port.network_id, port.id]) res = self.client.post(url, form_data) diff --git a/openstack_dashboard/dashboards/project/networks/ports/views.py b/openstack_dashboard/dashboards/project/networks/ports/views.py index 4fc16c9981..b42adceec1 100644 --- a/openstack_dashboard/dashboards/project/networks/ports/views.py +++ b/openstack_dashboard/dashboards/project/networks/ports/views.py @@ -195,4 +195,6 @@ class UpdateView(forms.ModalFormView): except Exception: # MAC Learning is not set pass + if 'port_security_enabled' in port: + initial['port_security_enabled'] = port['port_security_enabled'] return initial diff --git a/releasenotes/notes/port-security-81278703eae4f927.yaml b/releasenotes/notes/port-security-81278703eae4f927.yaml new file mode 100644 index 0000000000..2d7aae5dd0 --- /dev/null +++ b/releasenotes/notes/port-security-81278703eae4f927.yaml @@ -0,0 +1,6 @@ +--- +features: + - "Now it is possible to enable/disable port security in Horizon, when + the port-security extension is available. Note: Neutron allows disabling + the port security on a port only when no security groups are associated + to it"