Drop the legacy way to retrieve neutron quotas and usages

quota_details neutron API extension was implemented since Pike
and the enough migration period has passed. We have not received
any negative feedback on the removal of the legacy way since
its deprecation in Ussuri release.

Change-Id: Ia249e83a7d40af873d6509c932b11cb9bb7a9497
This commit is contained in:
Akihiro Motoki 2020-10-26 16:53:55 +09:00
parent b89c705164
commit 22741aaa3e
3 changed files with 15 additions and 229 deletions

View File

@ -432,23 +432,6 @@ class QuotaTests(test.APITestCase):
else: else:
self.mock_cinder_tenant_absolute_limits.assert_not_called() self.mock_cinder_tenant_absolute_limits.assert_not_called()
def test_tenant_quota_usages_neutron_with_target_network_resources(self):
self._test_tenant_quota_usages_neutron_with_target(
targets=('network', 'subnet', 'router',))
def test_tenant_quota_usages_neutron_with_target_security_groups(self):
self._test_tenant_quota_usages_neutron_with_target(
targets=('security_group',))
def test_tenant_quota_usages_neutron_with_target_floating_ips(self):
self._test_tenant_quota_usages_neutron_with_target(
targets=('floatingip',))
def test_tenant_quota_usages_neutron_with_target_security_group_rule(self):
self._test_tenant_quota_usages_neutron_with_target(
targets=('security_group_rule',)
)
def _list_security_group_rules(self): def _list_security_group_rules(self):
security_groups = self.security_groups.list() security_groups = self.security_groups.list()
security_group_rules = [] security_group_rules = []
@ -464,7 +447,7 @@ class QuotaTests(test.APITestCase):
api.neutron: ('is_extension_supported', api.neutron: ('is_extension_supported',
'is_quotas_extension_supported', 'is_quotas_extension_supported',
'tenant_quota_detail_get')}) 'tenant_quota_detail_get')})
def test_tenant_quota_usages_non_legacy(self): def test_tenant_quota_usages_network(self):
self._mock_service_enabled(network_enabled=True) self._mock_service_enabled(network_enabled=True)
self.mock_is_extension_supported.return_value = True self.mock_is_extension_supported.return_value = True
self.mock_is_quotas_extension_supported.return_value = True self.mock_is_quotas_extension_supported.return_value = True
@ -517,149 +500,14 @@ class QuotaTests(test.APITestCase):
# as _mock_service_enabled() requires it, but it is never called here. # as _mock_service_enabled() requires it, but it is never called here.
self.mock_is_volume_service_enabled.assert_not_called() self.mock_is_volume_service_enabled.assert_not_called()
self.mock_is_extension_supported.assert_has_calls([ self.mock_is_extension_supported.assert_has_calls([
# network
mock.call(test.IsHttpRequest(), 'quota_details'),
# subnet
mock.call(test.IsHttpRequest(), 'quota_details'),
# port
mock.call(test.IsHttpRequest(), 'quota_details'),
# router
mock.call(test.IsHttpRequest(), 'router'), mock.call(test.IsHttpRequest(), 'router'),
mock.call(test.IsHttpRequest(), 'quota_details'),
# floating IP
mock.call(test.IsHttpRequest(), 'quota_details'),
# security group
mock.call(test.IsHttpRequest(), 'security-group'), mock.call(test.IsHttpRequest(), 'security-group'),
mock.call(test.IsHttpRequest(), 'quota_details'),
# security group rule
mock.call(test.IsHttpRequest(), 'security-group'), mock.call(test.IsHttpRequest(), 'security-group'),
mock.call(test.IsHttpRequest(), 'quota_details'),
]) ])
self.assertEqual(10, self.mock_is_extension_supported.call_count) self.assertEqual(3, self.mock_is_extension_supported.call_count)
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_is_quotas_extension_supported, len(test_data), self.mock_is_quotas_extension_supported, len(test_data),
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_tenant_quota_detail_get, len(test_data), self.mock_tenant_quota_detail_get, len(test_data),
mock.call(test.IsHttpRequest(), self.request.user.tenant_id)) mock.call(test.IsHttpRequest(), self.request.user.tenant_id))
@test.create_mocks({api.base: ('is_service_enabled',),
cinder: ('is_volume_service_enabled',),
api.neutron: ('floating_ip_supported',
'tenant_floating_ip_list',
'security_group_list',
'is_extension_supported',
'is_router_enabled',
'is_quotas_extension_supported',
'tenant_quota_get',
'network_list',
'subnet_list',
'router_list')})
def _test_tenant_quota_usages_neutron_with_target(self, targets):
self._mock_service_enabled(network_enabled=True)
if 'security_group' in targets or 'security_group_rule' in targets:
self.mock_is_extension_supported.side_effect = [True, False]
else:
self.mock_is_extension_supported.side_effect = [False]
self.mock_is_router_enabled.return_value = True
self.mock_is_quotas_extension_supported.return_value = True
self.mock_tenant_quota_get.return_value = self.neutron_quotas.first()
if 'network' in targets:
self.mock_network_list.return_value = self.networks.list()
if 'subnet' in targets:
self.mock_subnet_list.return_value = self.subnets.list()
if 'router' in targets:
self.mock_router_list.return_value = self.routers.list()
if 'floatingip' in targets:
self.mock_tenant_floating_ip_list.return_value = \
self.floating_ips.list()
if 'security_group' in targets or 'security_group_rule' in targets:
self.mock_security_group_list.return_value = \
self.security_groups.list()
quota_usages = quotas.tenant_quota_usages(self.request,
targets=targets)
network_used = len(self.networks.list())
subnet_used = len(self.subnets.list())
router_used = len(self.routers.list())
fip_used = len(self.floating_ips.list())
security_groups = self.security_groups.list()
sg_used = len(security_groups)
sgr_used = sum(map(
lambda group: len(group.security_group_rules),
security_groups
))
expected = {
'network': {'used': network_used, 'quota': 10,
'available': 10 - network_used},
'subnet': {'used': subnet_used, 'quota': 10,
'available': 10 - subnet_used},
'router': {'used': router_used, 'quota': 10,
'available': 10 - router_used},
'security_group': {'used': sg_used, 'quota': 20,
'available': 20 - sg_used},
'security_group_rule': {
'quota': 100, 'used': sgr_used, 'available': 100 - sgr_used
},
'floatingip': {'used': fip_used, 'quota': 50,
'available': 50 - fip_used},
}
expected = dict((k, v) for k, v in expected.items() if k in targets)
# Compare internal structure of usages to expected.
self.assertEqual(expected, quota_usages.usages)
# Compare available resources
self.assertAvailableQuotasEqual(expected, quota_usages.usages)
self._check_service_enabled({'network': 1})
if 'security_group' in targets or 'security_group_rule' in targets:
self.mock_is_extension_supported.assert_has_calls([
mock.call(test.IsHttpRequest(), 'security-group'),
mock.call(test.IsHttpRequest(), 'quota_details'),
])
self.assertEqual(2, self.mock_is_extension_supported.call_count)
else:
self.mock_is_extension_supported.assert_called_once_with(
test.IsHttpRequest(), 'quota_details')
if 'floatingip' in targets or 'router' in targets:
self.mock_is_router_enabled.assert_called_once_with(
test.IsHttpRequest())
else:
self.mock_is_router_enabled.assert_not_called()
self.mock_is_quotas_extension_supported.assert_called_once_with(
test.IsHttpRequest())
self.mock_tenant_quota_get.assert_called_once_with(
test.IsHttpRequest(), '1')
if 'network' in targets:
self.mock_network_list.assert_called_once_with(
test.IsHttpRequest(),
tenant_id=self.request.user.tenant_id)
else:
self.mock_network_list.assert_not_called()
if 'subnet' in targets:
self.mock_subnet_list.assert_called_once_with(
test.IsHttpRequest(),
tenant_id=self.request.user.tenant_id)
else:
self.mock_subnet_list.assert_not_called()
if 'router' in targets:
self.mock_router_list.assert_called_once_with(
test.IsHttpRequest(),
tenant_id=self.request.user.tenant_id)
else:
self.mock_router_list.assert_not_called()
if 'floatingip' in targets:
self.mock_tenant_floating_ip_list.assert_called_once_with(
test.IsHttpRequest())
else:
self.mock_tenant_floating_ip_list.assert_not_called()
if 'security_group' in targets or 'security_group_rule' in targets:
self.mock_security_group_list.assert_called_once_with(
test.IsHttpRequest())
else:
self.mock_security_group_list.assert_not_called()

View File

@ -13,7 +13,6 @@
from collections import defaultdict from collections import defaultdict
import itertools import itertools
import logging import logging
import warnings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -337,7 +336,6 @@ def _get_tenant_network_usages(request, usages, disabled_quotas, tenant_id):
if not enabled_quotas: if not enabled_quotas:
return return
if neutron.is_extension_supported(request, 'quota_details'):
details = neutron.tenant_quota_detail_get(request, tenant_id) details = neutron.tenant_quota_detail_get(request, tenant_id)
for quota_name in NEUTRON_QUOTA_FIELDS: for quota_name in NEUTRON_QUOTA_FIELDS:
if quota_name in disabled_quotas: if quota_name in disabled_quotas:
@ -345,73 +343,6 @@ def _get_tenant_network_usages(request, usages, disabled_quotas, tenant_id):
detail = details[quota_name] detail = details[quota_name]
usages.add_quota(base.Quota(quota_name, detail['limit'])) usages.add_quota(base.Quota(quota_name, detail['limit']))
usages.tally(quota_name, detail['used'] + detail['reserved']) usages.tally(quota_name, detail['used'] + detail['reserved'])
else:
_get_tenant_network_usages_legacy(
request, usages, disabled_quotas, tenant_id)
def _get_neutron_quota_data(request, qs, disabled_quotas, tenant_id):
tenant_id = tenant_id or request.user.tenant_id
neutron_quotas = neutron.tenant_quota_get(request, tenant_id)
for quota_name in NEUTRON_QUOTA_FIELDS:
if quota_name not in disabled_quotas:
quota_data = neutron_quotas.get(quota_name).limit
qs.add(base.QuotaSet({quota_name: quota_data}))
return qs
# TODO(amotoki): Deprecated in Ussuri. Drop this in Victoria release or later.
def _get_tenant_network_usages_legacy(request, usages, disabled_quotas,
tenant_id):
warnings.warn(
"The legacy way to retrieve neutron resource usage is deprecated "
"in Ussuri release. Horizon will depend on 'quota_details' "
"neutron extension added in Pike release in future.",
DeprecationWarning)
qs = base.QuotaSet()
_get_neutron_quota_data(request, qs, disabled_quotas, tenant_id)
for quota in qs:
usages.add_quota(quota)
resource_lister = {
'network': (neutron.network_list, {'tenant_id': tenant_id}),
'subnet': (neutron.subnet_list, {'tenant_id': tenant_id}),
'port': (neutron.port_list, {'tenant_id': tenant_id}),
'router': (neutron.router_list, {'tenant_id': tenant_id}),
'floatingip': (neutron.tenant_floating_ip_list, {}),
}
for quota_name, lister_info in resource_lister.items():
if quota_name not in disabled_quotas:
lister = lister_info[0]
kwargs = lister_info[1]
try:
resources = lister(request, **kwargs)
except Exception:
resources = []
usages.tally(quota_name, len(resources))
# Security groups have to be processed separately so that rules may be
# processed in the same api call and in a single pass
add_sg = 'security_group' not in disabled_quotas
add_sgr = 'security_group_rule' not in disabled_quotas
if add_sg or add_sgr:
try:
security_groups = neutron.security_group_list(request)
num_rules = sum(len(group['security_group_rules'])
for group in security_groups)
except Exception:
security_groups = []
num_rules = 0
if add_sg:
usages.tally('security_group', len(security_groups))
if add_sgr:
usages.tally('security_group_rule', num_rules)
@profiler.trace @profiler.trace

View File

@ -0,0 +1,7 @@
---
upgrade:
- |
The legacy way to retrive neutron resource usages was dropped and
horizon now assumes the ``quota_details`` neutron API extension
implemented in Pike release (over three years ago), so we expect
this is available in all Wallaby neutron deployments.