Merge "Drop the legacy way to retrieve neutron quotas and usages"

This commit is contained in:
Zuul 2020-11-18 18:08:06 +00:00 committed by Gerrit Code Review
commit d6ab5431ba
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,81 +336,13 @@ 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:
if quota_name in disabled_quotas:
continue
detail = details[quota_name]
usages.add_quota(base.Quota(quota_name, detail['limit']))
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: for quota_name in NEUTRON_QUOTA_FIELDS:
if quota_name not in disabled_quotas: if quota_name in disabled_quotas:
quota_data = neutron_quotas.get(quota_name).limit continue
qs.add(base.QuotaSet({quota_name: quota_data})) detail = details[quota_name]
usages.add_quota(base.Quota(quota_name, detail['limit']))
return qs usages.tally(quota_name, detail['used'] + detail['reserved'])
# 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.