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:
parent
b89c705164
commit
22741aaa3e
@ -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()
|
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user