Merge "Drop the legacy way to retrieve neutron quotas and usages"
This commit is contained in:
commit
d6ab5431ba
@ -432,23 +432,6 @@ class QuotaTests(test.APITestCase):
|
||||
else:
|
||||
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):
|
||||
security_groups = self.security_groups.list()
|
||||
security_group_rules = []
|
||||
@ -464,7 +447,7 @@ class QuotaTests(test.APITestCase):
|
||||
api.neutron: ('is_extension_supported',
|
||||
'is_quotas_extension_supported',
|
||||
'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_is_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.
|
||||
self.mock_is_volume_service_enabled.assert_not_called()
|
||||
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(), 'quota_details'),
|
||||
# floating IP
|
||||
mock.call(test.IsHttpRequest(), 'quota_details'),
|
||||
# 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(), '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.mock_is_quotas_extension_supported, len(test_data),
|
||||
mock.call(test.IsHttpRequest()))
|
||||
self.assert_mock_multiple_calls_with_same_arguments(
|
||||
self.mock_tenant_quota_detail_get, len(test_data),
|
||||
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
|
||||
import itertools
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
if neutron.is_extension_supported(request, 'quota_details'):
|
||||
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)
|
||||
|
||||
details = neutron.tenant_quota_detail_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)
|
||||
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'])
|
||||
|
||||
|
||||
@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