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:
|
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