From 78574736a52656c6d9fba92634bf58e0ad03915a Mon Sep 17 00:00:00 2001 From: Shilpa Devharakar Date: Thu, 22 Aug 2019 14:29:41 +0530 Subject: Add Allowed Address Pair/Delete buttons are only visible to admin Initially In Queens, when logging into Horizon in context of a _member_ in any project, the "Add Allowed Address Pair" and "Delete" buttons in "Network" -> "Networks" -> -> "Allowed Address Pairs" are not visible. When accessing the same panel in context of a project where the user has the admin role, the "Add" and "Delete" button is visible and functional. This patch fixes the above issue by updating the policy_target. Change-Id: Ia7db6c2881c72580a156eb97b11bb51f295cfbce Closes-Bug: #1794421 (cherry picked from commit 87b57dfe7113da09715d5613ab9c91c15a75c189) --- .../dashboards/admin/networks/ports/tests.py | 48 ++++++++ .../extensions/allowed_address_pairs/tables.py | 16 +++ .../dashboards/project/networks/ports/tests.py | 122 +++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/openstack_dashboard/dashboards/admin/networks/ports/tests.py b/openstack_dashboard/dashboards/admin/networks/ports/tests.py index 9048e17d4..57676f18f 100644 --- a/openstack_dashboard/dashboards/admin/networks/ports/tests.py +++ b/openstack_dashboard/dashboards/admin/networks/ports/tests.py @@ -15,6 +15,7 @@ import collections +from django.test.utils import override_settings from django.urls import reverse import mock @@ -613,3 +614,50 @@ class NetworkPortTests(test.BaseAdminViewTests): self._check_is_extension_supported( {'network-ip-availability': 1, 'mac-learning': 1}) + + @override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check') + @test.create_mocks({api.neutron: ('port_get', + 'network_get', + 'is_extension_supported')}) + def test_add_allowed_address_pair_button_shown(self): + port = self.ports.first() + url = reverse('horizon:project:networks:ports:addallowedaddresspairs', + args=[port.id]) + classes = 'btn data-table-action btn-default ajax-modal' + link_name = "Add Allowed Address Pair" + + expected_string = \ + '' \ + ' %s' \ + % (classes, url, link_name) + + res = self.client.get(reverse('horizon:project:networks:ports:detail', + args=[port.id])) + + self.assertTemplateUsed(res, 'horizon/common/_detail_tab_group.html') + self.assertIn(expected_string, res.context_data['tab_group'].render()) + + @override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check') + @test.create_mocks({api.neutron: ('port_get', + 'network_get', + 'port_update', + 'is_extension_supported')}) + def test_delete_address_pair_button_shown(self): + port = self.ports.first() + classes = 'data-table-action btn-danger btn' + + expected_string = \ + '' \ + % (classes) + + res = self.client.get(reverse( + 'horizon:project:networks:ports:detail', args=[port.id])) + + self.assertTemplateUsed(res, 'horizon/common/_detail_tab_group.html') + self.assertIn(expected_string, res.context_data['tab_group'].render()) diff --git a/openstack_dashboard/dashboards/project/networks/ports/extensions/allowed_address_pairs/tables.py b/openstack_dashboard/dashboards/project/networks/ports/extensions/allowed_address_pairs/tables.py index bdea18991..d90c61ea2 100644 --- a/openstack_dashboard/dashboards/project/networks/ports/extensions/allowed_address_pairs/tables.py +++ b/openstack_dashboard/dashboards/project/networks/ports/extensions/allowed_address_pairs/tables.py @@ -39,6 +39,14 @@ class AddAllowedAddressPair(policy.PolicyTargetMixin, tables.LinkAction): ("network", "update_port:allowed_address_pairs"), ) + def get_policy_target(self, request, datum=None): + policy_target = super(AddAllowedAddressPair, self).\ + get_policy_target(request, datum) + policy_target["network:tenant_id"] = ( + self.table.kwargs['port'].tenant_id) + + return policy_target + def get_link_url(self, port=None): if port: return reverse(self.url, args=(port.id,)) @@ -68,6 +76,14 @@ class DeleteAllowedAddressPair(tables.DeleteAction): ("network", "update_port:allowed_address_pairs"), ) + def get_policy_target(self, request, datum=None): + policy_target = super(DeleteAllowedAddressPair, self).\ + get_policy_target(request, datum) + policy_target["network:tenant_id"] = ( + self.table.kwargs['port'].tenant_id) + + return policy_target + def delete(self, request, ip_address): try: port_id = self.table.kwargs['port_id'] diff --git a/openstack_dashboard/dashboards/project/networks/ports/tests.py b/openstack_dashboard/dashboards/project/networks/ports/tests.py index 544f18d07..b0348797d 100644 --- a/openstack_dashboard/dashboards/project/networks/ports/tests.py +++ b/openstack_dashboard/dashboards/project/networks/ports/tests.py @@ -16,10 +16,13 @@ import collections import copy +from django.test.utils import override_settings from django.urls import reverse import mock +from openstack_auth import utils as auth_utils + from horizon.workflows import views from openstack_dashboard import api @@ -288,6 +291,66 @@ class NetworkPortTests(test.TestCase): self.mock_network_get.assert_called_once_with( test.IsHttpRequest(), network.id) + @override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check') + @test.create_mocks({api.neutron: ('port_get', + 'network_get', + 'is_extension_supported')}) + def test_add_allowed_address_pair_button_shown_to_network_owner(self): + port = self.ports.first() + + url = reverse('horizon:project:networks:ports:addallowedaddresspairs', + args=[port.id]) + classes = 'btn data-table-action btn-default ajax-modal' + link_name = "Add Allowed Address Pair" + + expected_string = \ + '' \ + ' %s' \ + % (classes, url, link_name) + + res = self.client.get(reverse('horizon:project:networks:ports:detail', + args=[port.id])) + + self.assertTemplateUsed(res, 'horizon/common/_detail_tab_group.html') + self.assertIn(expected_string, res.context_data['tab_group'].render()) + + @override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check') + @test.create_mocks({api.neutron: ('port_get', + 'network_get', + 'is_extension_supported')}) + def test_add_allowed_address_pair_button_disabled_to_other_tenant(self): + # Current user tenant_id is 1 so select port whose tenant_id is + # other than 1 for checking "Add Allowed Address Pair" button is not + # displayed on the screen. + user = auth_utils.get_user(self.request) + + # select port such that tenant_id is different from user's tenant_id. + port = [p for p in self.ports.list() + if p.tenant_id != user.tenant_id][0] + + self._stub_is_extension_supported( + {'allowed-address-pairs': False, 'mac-learning': False}) + + with mock.patch('openstack_auth.utils.get_user', return_value=user): + url = reverse( + 'horizon:project:networks:ports:addallowedaddresspairs', + args=[port.id]) + classes = 'btn data-table-action btn-default ajax-modal' + link_name = "Add Allowed Address Pair" + + expected_string = \ + '' \ + ' %s' \ + % (classes, url, link_name) + + res = self.client.get(reverse( + 'horizon:project:networks:ports:detail', args=[port.id])) + + self.assertNotIn( + expected_string, res.context_data['tab_group'].render()) + @test.create_mocks({api.neutron: ('port_get', 'port_update')}) def test_port_add_allowed_address_pair(self): @@ -345,6 +408,65 @@ class NetworkPortTests(test.TestCase): self.assertFormErrors(res, 1) self.assertContains(res, "Incorrect format for IP address") + @override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check') + @test.create_mocks({api.neutron: ('port_get', + 'network_get', + 'port_update', + 'is_extension_supported')}) + def test_delete_address_pair_button_shown_to_network_owner(self): + port = self.ports.first() + classes = 'data-table-action btn-danger btn' + + expected_string = \ + '' \ + % (classes) + + res = self.client.get(reverse( + 'horizon:project:networks:ports:detail', args=[port.id])) + + self.assertTemplateUsed(res, 'horizon/common/_detail_tab_group.html') + self.assertIn(expected_string, res.context_data['tab_group'].render()) + + @override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check') + @test.create_mocks({api.neutron: ('port_get', + 'network_get', + 'is_extension_supported')}) + def test_delete_address_pair_button_disabled_to_other_tenant(self): + # Current user tenant_id is 1 so select port whose tenant_id is + # other than 1 for checking "Delete Allowed Address Pair" button is + # not displayed on the screen. + user = auth_utils.get_user(self.request) + + # select port such that tenant_id is different from user's tenant_id. + port = [p for p in self.ports.list() + if p.tenant_id != user.tenant_id][0] + + self._stub_is_extension_supported( + {'allowed-address-pairs': False, 'mac-learning': False}) + + with mock.patch('openstack_auth.utils.get_user', return_value=user): + classes = 'data-table-action btn-danger btn' + + expected_string = \ + '' % (classes) + + res = self.client.get(reverse( + 'horizon:project:networks:ports:detail', args=[port.id])) + + self.assertNotIn( + expected_string, res.context_data['tab_group'].render()) + @test.create_mocks({api.neutron: ('port_get', 'is_extension_supported', 'port_update')}) -- cgit v1.2.1