From ce950e4eb44aeb1c344f7b1037f5cacea37b6ebe Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Mon, 27 Nov 2023 12:34:40 +0100 Subject: [PATCH] Remove quota checks from admin network dashboards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the checks for quota for network, subnetwork, and port create actions in the admin dashboards. While the checks are a nice feature in the project daashboard, where they result in only one call, because only one tenant needs to be checked, on the admin dashboard those checks are too expensive — there is one for every tenant that has a network. This is unacceptable on clouds that have hundreds of tenants, and in addition it exhausts the default limit for memoization (25), resulting in many other extra calls. The effect of this is that the create action will no longer be grayed out when the given user runs out of quota. This doesn't matter for the admin user. If they try to perform the action, they will get a quota error anyways. This patch should significantly speed up the admin dashboards on large clouds with a lot of tenants. Change-Id: I67447bad868f29022c5247c2193ec804dc2a0518 --- .../dashboards/admin/networks/ports/tables.py | 13 --- .../admin/networks/subnets/tables.py | 15 ---- .../admin/networks/subnets/tests.py | 12 +-- .../dashboards/admin/networks/tables.py | 14 ---- .../dashboards/admin/networks/tests.py | 80 +++---------------- 5 files changed, 13 insertions(+), 121 deletions(-) diff --git a/openstack_dashboard/dashboards/admin/networks/ports/tables.py b/openstack_dashboard/dashboards/admin/networks/ports/tables.py index e638eeb74e..5b81b03d1c 100644 --- a/openstack_dashboard/dashboards/admin/networks/ports/tables.py +++ b/openstack_dashboard/dashboards/admin/networks/ports/tables.py @@ -24,7 +24,6 @@ from openstack_dashboard.dashboards.project.networks.ports import \ tables as project_tables from openstack_dashboard.dashboards.project.networks.ports.tabs \ import PortsTab as project_port_tab -from openstack_dashboard.usage import quotas class DeletePort(project_tables.DeletePort): @@ -35,18 +34,6 @@ class CreatePort(project_tables.CreatePort): url = "horizon:admin:networks:addport" def allowed(self, request, datum=None): - network = self.table._get_network() - tenant_id = network.tenant_id - usages = quotas.tenant_quota_usages( - request, tenant_id=tenant_id, targets=('port', )) - if usages.get('port', {}).get('available', 1) <= 0: - if "disabled" not in self.classes: - self.classes = list(self.classes) + ['disabled'] - self.verbose_name = _("Create Port (Quota exceeded)") - else: - self.verbose_name = _("Create Port") - self.classes = [c for c in self.classes if c != "disabled"] - return True diff --git a/openstack_dashboard/dashboards/admin/networks/subnets/tables.py b/openstack_dashboard/dashboards/admin/networks/subnets/tables.py index 4c867f538b..2068d8ad17 100644 --- a/openstack_dashboard/dashboards/admin/networks/subnets/tables.py +++ b/openstack_dashboard/dashboards/admin/networks/subnets/tables.py @@ -27,7 +27,6 @@ from openstack_dashboard.dashboards.project.networks.subnets \ import tables as proj_tables from openstack_dashboard.dashboards.project.networks.subnets.tabs \ import SubnetsTab as project_tabs_subnets_tab -from openstack_dashboard.usage import quotas LOG = logging.getLogger(__name__) @@ -45,20 +44,6 @@ class CreateSubnet(proj_tables.SubnetPolicyTargetMixin, tables.LinkAction): return reverse(self.url, args=(network_id,)) def allowed(self, request, datum=None): - network = self.table._get_network() - usages = quotas.tenant_quota_usages( - request, tenant_id=network.tenant_id, targets=('subnet', )) - - # when Settings.OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False - # usages["subnet'] is empty - if usages.get('subnet', {}).get('available', 1) <= 0: - if 'disabled' not in self.classes: - self.classes = list(self.classes) + ['disabled'] - self.verbose_name = _('Create Subnet (Quota exceeded)') - else: - self.verbose_name = _('Create Subnet') - self.classes = [c for c in self.classes if c != 'disabled'] - return True diff --git a/openstack_dashboard/dashboards/admin/networks/subnets/tests.py b/openstack_dashboard/dashboards/admin/networks/subnets/tests.py index 4f9478d534..a600bbb032 100644 --- a/openstack_dashboard/dashboards/admin/networks/subnets/tests.py +++ b/openstack_dashboard/dashboards/admin/networks/subnets/tests.py @@ -24,7 +24,6 @@ from horizon.workflows import views from openstack_dashboard import api from openstack_dashboard.dashboards.project.networks import tests from openstack_dashboard.test import helpers as test -from openstack_dashboard.usage import quotas DETAIL_URL = 'horizon:admin:networks:subnets:detail' @@ -393,12 +392,10 @@ class NetworkSubnetTests(test.BaseAdminViewTests): @test.create_mocks({api.neutron: ('network_get', 'subnet_list', 'is_extension_supported', - 'show_network_ip_availability'), - quotas: ('tenant_quota_usages',)}) + 'show_network_ip_availability')}) def _test_network_detail_ip_availability_exception(self, mac_learning=False): network = self.networks.first() - quota_data = self.neutron_quota_usages.first() self._stub_is_extension_supported( {'network-ip-availability': True, @@ -409,7 +406,6 @@ class NetworkSubnetTests(test.BaseAdminViewTests): self.exceptions.neutron self.mock_network_get.return_value = network self.mock_subnet_list.return_value = [self.subnets.first()] - self.mock_tenant_quota_usages.return_value = quota_data url = parse.unquote(reverse('horizon:admin:networks:subnets_tab', args=[network.id])) @@ -426,11 +422,7 @@ class NetworkSubnetTests(test.BaseAdminViewTests): self.mock_show_network_ip_availability.assert_called_once_with( test.IsHttpRequest(), network.id) self.assert_mock_multiple_calls_with_same_arguments( - self.mock_network_get, 2, + self.mock_network_get, 1, mock.call(test.IsHttpRequest(), network.id)) self.mock_subnet_list.assert_called_once_with(test.IsHttpRequest(), network_id=network.id) - self.assert_mock_multiple_calls_with_same_arguments( - self.mock_tenant_quota_usages, 3, - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',))) diff --git a/openstack_dashboard/dashboards/admin/networks/tables.py b/openstack_dashboard/dashboards/admin/networks/tables.py index b8f3f977c1..2c4499d078 100644 --- a/openstack_dashboard/dashboards/admin/networks/tables.py +++ b/openstack_dashboard/dashboards/admin/networks/tables.py @@ -25,7 +25,6 @@ from openstack_dashboard import api from openstack_dashboard.dashboards.project.networks \ import tables as project_tables from openstack_dashboard import policy -from openstack_dashboard.usage import quotas LOG = logging.getLogger(__name__) @@ -52,19 +51,6 @@ class CreateSubnet(project_tables.CreateSubnet): url = "horizon:admin:networks:createsubnet" def allowed(self, request, datum=None): - usages = quotas.tenant_quota_usages( - request, tenant_id=datum.tenant_id, targets=('subnet', )) - - # when Settings.OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False - # usages["subnet'] is empty - if usages.get('subnet', {}).get('available', 1) <= 0: - if 'disabled' not in self.classes: - self.classes = list(self.classes) + ['disabled'] - self.verbose_name = _('Create Subnet (Quota exceeded)') - else: - self.verbose_name = _('Create Subnet') - self.classes = [c for c in self.classes if c != 'disabled'] - return True diff --git a/openstack_dashboard/dashboards/admin/networks/tests.py b/openstack_dashboard/dashboards/admin/networks/tests.py index 7f7973c9e3..f415d84b0a 100644 --- a/openstack_dashboard/dashboards/admin/networks/tests.py +++ b/openstack_dashboard/dashboards/admin/networks/tests.py @@ -23,7 +23,6 @@ from horizon import forms from openstack_dashboard import api from openstack_dashboard.dashboards.project.networks import tests from openstack_dashboard.test import helpers as test -from openstack_dashboard import usage INDEX_TEMPLATE = 'horizon/common/_data_table_view.html' INDEX_URL = reverse('horizon:admin:networks:index') @@ -47,18 +46,15 @@ class NetworkTests(test.BaseAdminViewTests): @test.create_mocks({api.neutron: ('network_list', 'list_dhcp_agent_hosting_networks', 'is_extension_supported'), - api.keystone: ('tenant_list',), - usage.quotas: ('tenant_quota_usages',)}) + api.keystone: ('tenant_list',)}) def test_index(self): tenants = self.tenants.list() - quota_data = self.quota_usages.first() self.mock_network_list.return_value = self.networks.list() self.mock_tenant_list.return_value = [tenants, False] self._stub_is_extension_supported( {'network_availability_zone': True, 'dhcp_agent_scheduler': True}) - self.mock_tenant_quota_usages.return_value = quota_data self.mock_list_dhcp_agent_hosting_networks.return_value = \ self.agents.list() @@ -75,12 +71,6 @@ class NetworkTests(test.BaseAdminViewTests): self._check_is_extension_supported( {'network_availability_zone': 1, 'dhcp_agent_scheduler': len(self.networks.list()) + 1}) - self.mock_tenant_quota_usages.assert_has_calls( - [mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet', )) - for network in self.networks.list()]) - self.assertEqual(len(self.networks.list()), - self.mock_tenant_quota_usages.call_count) self.mock_list_dhcp_agent_hosting_networks.assert_has_calls( [mock.call(test.IsHttpRequest(), network.id) for network in self.networks.list()]) @@ -109,14 +99,11 @@ class NetworkTests(test.BaseAdminViewTests): 'dhcp_agent_scheduler': 1}) @test.create_mocks({api.neutron: ('network_get', - 'is_extension_supported'), - usage.quotas: ('tenant_quota_usages',)}) + 'is_extension_supported')}) def test_network_detail_new(self, mac_learning=False): network = self.networks.first() - quota_data = self.quota_usages.first() self.mock_network_get.return_value = network - self.mock_tenant_quota_usages.return_value = quota_data self._stub_is_extension_supported( {'network-ip-availability': True, 'network_availability_zone': True, @@ -133,12 +120,6 @@ class NetworkTests(test.BaseAdminViewTests): network.status_label) self.assertTemplateUsed(res, 'horizon/common/_detail.html') - self.assert_mock_multiple_calls_with_same_arguments( - self.mock_network_get, 2, - mock.call(test.IsHttpRequest(), network.id)) - self.mock_tenant_quota_usages.assert_called_once_with( - test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',)) self._check_is_extension_supported( {'network-ip-availability': 1, 'network_availability_zone': 1, @@ -154,12 +135,10 @@ class NetworkTests(test.BaseAdminViewTests): @test.create_mocks({api.neutron: ('network_get', 'subnet_list', 'show_network_ip_availability', - 'is_extension_supported'), - usage.quotas: ('tenant_quota_usages',)}) + 'is_extension_supported')}) def _test_network_detail_subnets_tab(self, mac_learning=False): network = self.networks.first() ip_availability = self.ip_availability.get() - quota_data = self.quota_usages.first() self.mock_show_network_ip_availability.return_value = ip_availability self.mock_network_get.return_value = network @@ -169,7 +148,6 @@ class NetworkTests(test.BaseAdminViewTests): 'mac-learning': mac_learning, 'network_availability_zone': True, 'dhcp_agent_scheduler': True}) - self.mock_tenant_quota_usages.return_value = quota_data url = parse.unquote(reverse('horizon:admin:networks:subnets_tab', args=[network.id])) @@ -182,7 +160,7 @@ class NetworkTests(test.BaseAdminViewTests): self.mock_show_network_ip_availability.assert_called_once_with( test.IsHttpRequest(), network.id) self.assert_mock_multiple_calls_with_same_arguments( - self.mock_network_get, 2, + self.mock_network_get, 1, mock.call(test.IsHttpRequest(), network.id)) self.mock_subnet_list.assert_called_once_with(test.IsHttpRequest(), network_id=network.id) @@ -191,22 +169,15 @@ class NetworkTests(test.BaseAdminViewTests): 'mac-learning': 1, 'network_availability_zone': 1, 'dhcp_agent_scheduler': 1}) - self.assert_mock_multiple_calls_with_same_arguments( - self.mock_tenant_quota_usages, 3, - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',))) @test.create_mocks({api.neutron: ('network_get', 'port_list', - 'is_extension_supported'), - usage.quotas: ('tenant_quota_usages',)}) + 'is_extension_supported')}) def test_network_detail_ports_tab(self, mac_learning=False): network = self.networks.first() - quota_data = self.neutron_quota_usages.first() self.mock_network_get.return_value = network self.mock_port_list.return_value = [self.ports.first()] - self.mock_tenant_quota_usages.return_value = quota_data self._stub_is_extension_supported( {'network-ip-availability': True, 'mac-learning': mac_learning, @@ -222,19 +193,10 @@ class NetworkTests(test.BaseAdminViewTests): self.assertCountEqual(ports, [self.ports.first()]) self.assert_mock_multiple_calls_with_same_arguments( - self.mock_network_get, 2, + self.mock_network_get, 1, mock.call(test.IsHttpRequest(), network.id)) self.mock_port_list.assert_called_once_with(test.IsHttpRequest(), network_id=network.id) - self.assertEqual(3, self.mock_tenant_quota_usages.call_count) - self.mock_tenant_quota_usages.assert_has_calls([ - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',)), - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('port',)), - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('port',)), - ]) self._check_is_extension_supported( {'network-ip-availability': 1, 'mac-learning': 1, @@ -243,11 +205,9 @@ class NetworkTests(test.BaseAdminViewTests): @test.create_mocks({api.neutron: ('network_get', 'is_extension_supported', - 'list_dhcp_agent_hosting_networks',), - usage.quotas: ('tenant_quota_usages',)}) + 'list_dhcp_agent_hosting_networks',)}) def test_network_detail_agents_tab(self, mac_learning=False): network = self.networks.first() - quota_data = self.quota_usages.first() self._stub_is_extension_supported( {'network-ip-availability': True, @@ -257,7 +217,6 @@ class NetworkTests(test.BaseAdminViewTests): self.mock_list_dhcp_agent_hosting_networks.return_value = \ self.agents.list() self.mock_network_get.return_value = network - self.mock_tenant_quota_usages.return_value = quota_data url = reverse('horizon:admin:networks:agents_tab', args=[network.id]) res = self.client.get(parse.unquote(url)) @@ -277,9 +236,6 @@ class NetworkTests(test.BaseAdminViewTests): test.IsHttpRequest(), network.id) self.mock_network_get.assert_called_once_with( test.IsHttpRequest(), network.id) - self.mock_tenant_quota_usages.assert_called_once_with( - test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',)) def test_network_detail_subnets_tab_network_exception(self): self._test_network_detail_subnets_tab_network_exception() @@ -331,12 +287,10 @@ class NetworkTests(test.BaseAdminViewTests): @test.create_mocks({api.neutron: ('network_get', 'subnet_list', 'show_network_ip_availability', - 'is_extension_supported'), - usage.quotas: ('tenant_quota_usages',)}) + 'is_extension_supported')}) def _test_network_detail_subnets_tab_subnet_exception(self, mac_learning=False): network = self.networks.first() - quota_data = self.quota_usages.first() self.mock_show_network_ip_availability.return_value = \ self.ip_availability.get() @@ -347,7 +301,6 @@ class NetworkTests(test.BaseAdminViewTests): 'mac-learning': mac_learning, 'dhcp_agent_scheduler': True, 'network_availability_zone': True}) - self.mock_tenant_quota_usages.return_value = quota_data url = parse.unquote(reverse('horizon:admin:networks:subnets_tab', args=[network.id])) @@ -360,14 +313,10 @@ class NetworkTests(test.BaseAdminViewTests): self.mock_show_network_ip_availability.assert_called_once_with( test.IsHttpRequest(), network.id) self.assert_mock_multiple_calls_with_same_arguments( - self.mock_network_get, 2, + self.mock_network_get, 1, mock.call(test.IsHttpRequest(), network.id)) self.mock_subnet_list.assert_called_once_with(test.IsHttpRequest(), network_id=network.id) - self.assert_mock_multiple_calls_with_same_arguments( - self.mock_tenant_quota_usages, 3, - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',))) self._stub_is_extension_supported( {'network-ip-availability': 1, 'mac-learning': 1, @@ -383,13 +332,11 @@ class NetworkTests(test.BaseAdminViewTests): @test.create_mocks({api.neutron: ('network_get', 'subnet_list', 'is_extension_supported', - 'show_network_ip_availability'), - usage.quotas: ('tenant_quota_usages',)}) + 'show_network_ip_availability')}) def _test_network_detail_subnets_tab_port_exception(self, mac_learning=False): network = self.networks.first() ip_availability = self.ip_availability.get() - quota_data = self.quota_usages.first() self.mock_show_network_ip_availability.return_value = ip_availability self.mock_network_get.return_value = network @@ -399,7 +346,6 @@ class NetworkTests(test.BaseAdminViewTests): 'mac-learning': mac_learning, 'network_availability_zone': True, 'dhcp_agent_scheduler': True}) - self.mock_tenant_quota_usages.return_value = quota_data url = parse.unquote(reverse('horizon:admin:networks:subnets_tab', args=[network.id])) @@ -412,7 +358,7 @@ class NetworkTests(test.BaseAdminViewTests): self.mock_show_network_ip_availability.assert_called_once_with( test.IsHttpRequest(), network.id) self.assert_mock_multiple_calls_with_same_arguments( - self.mock_network_get, 2, + self.mock_network_get, 1, mock.call(test.IsHttpRequest(), network.id)) self.mock_subnet_list.assert_called_once_with(test.IsHttpRequest(), network_id=network.id) @@ -421,10 +367,6 @@ class NetworkTests(test.BaseAdminViewTests): 'mac-learning': 1, 'network_availability_zone': 1, 'dhcp_agent_scheduler': 1}) - self.assert_mock_multiple_calls_with_same_arguments( - self.mock_tenant_quota_usages, 3, - mock.call(test.IsHttpRequest(), tenant_id=network.tenant_id, - targets=('subnet',))) @test.create_mocks({api.neutron: ('is_extension_supported',), api.keystone: ('tenant_list',)})