Merge "Rework limits normalization"

This commit is contained in:
Jenkins 2017-01-10 19:00:10 +00:00 committed by Gerrit Code Review
commit 114d4af140
6 changed files with 101 additions and 28 deletions

View File

@ -191,6 +191,30 @@ A Server from Nova
task_state=str() or None,
properties=dict())
ComputeLimits
-------------
Limits and current usage for a project in Nova
.. code-block:: python
ComputeLimits = dict(
location=Location(),
max_personality=int(),
max_personality_size=int(),
max_server_group_members=int(),
max_server_groups=int(),
max_server_meta=int(),
max_total_cores=int(),
max_total_instances=int(),
max_total_keypairs=int(),
max_total_ram_size=int(),
total_cores_used=int(),
total_instances_used=int(),
total_ram_used=int(),
total_server_groups_used=int(),
properties=dict())
Floating IP
-----------

View File

@ -45,6 +45,22 @@ _SERVER_FIELDS = (
'user_id',
)
_COMPUTE_LIMITS_FIELDS = (
('maxPersonality', 'max_personality'),
('maxPersonalitySize', 'max_personality_size'),
('maxServerGroupMembers', 'max_server_group_members'),
('maxServerGroups', 'max_server_groups'),
('maxServerMeta', 'max_server_meta'),
('maxTotalCores', 'max_total_cores'),
('maxTotalInstances', 'max_total_instances'),
('maxTotalKeypairs', 'max_total_keypairs'),
('maxTotalRAMSize', 'max_total_ram_size'),
('totalCoresUsed', 'total_cores_used'),
('totalInstancesUsed', 'total_instances_used'),
('totalRAMUsed', 'total_ram_used'),
('totalServerGroupsUsed', 'total_server_groups_used'),
)
_pushdown_fields = {
'project': [
@ -106,14 +122,23 @@ class Normalizer(object):
reasons.
'''
def _normalize_limits(self, limits):
def _normalize_compute_limits(self, limits, project_id=None):
""" Normalize a limits object.
Limits modified in this method and shouldn't be modified afterwards.
"""
new_limits = munch.Munch(limits['absolute'])
new_limits['rate'] = limits.pop('rate')
# Copy incoming limits because of shared dicts in unittests
limits = limits['absolute'].copy()
new_limits = munch.Munch()
new_limits['location'] = self._get_current_location(
project_id=project_id)
for field in _COMPUTE_LIMITS_FIELDS:
new_limits[field[1]] = limits.pop(field[0], None)
new_limits['properties'] = limits.copy()
return new_limits

View File

@ -1778,6 +1778,34 @@ class OpenStackCloud(_normalize.Normalizer):
with _utils.shade_exceptions("Error fetching server group list"):
return self.manager.submit_task(_tasks.ServerGroupList())
def get_compute_limits(self, name_or_id=None):
""" Get compute limits for a project
:param name_or_id: (optional) project name or id to get limits for
if different from the current project
:raises: OpenStackCloudException if it's not a valid project
:returns: Munch object with the limits
"""
kwargs = {}
project_id = None
if name_or_id:
proj = self.get_project(name_or_id)
if not proj:
raise OpenStackCloudException("project does not exist")
project_id = proj.id
kwargs['tenant_id'] = project_id
with _utils.shade_exceptions(
"Failed to get limits for the project: {} ".format(
name_or_id)):
# TODO(mordred) Before we convert this to REST, we need to add
# in support for running calls with a different project context
limits = self.manager.submit_task(_tasks.NovaLimitsGet(**kwargs))
return self._normalize_compute_limits(limits, project_id=project_id)
@_utils.cache_on_arguments(should_cache_fn=_no_pending_images)
def list_images(self, filter_deleted=True):
"""Get available glance images.

View File

@ -2141,22 +2141,3 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
with _utils.shade_exceptions("Error fetching Magnum services list"):
return self.manager.submit_task(
_tasks.MagnumServicesList())
def get_limits(self, name_or_id):
""" Get limits for a project
:param name_or_id: project name or id
:raises: OpenStackCloudException if it's not a valid project
:returns: Munch object with the limits
"""
proj = self.get_project(name_or_id)
if not proj.id:
raise OpenStackCloudException("project does not exist")
with _utils.shade_exceptions(
"Failed to get limits for the project: {} ".format(proj.id)):
limits = self.manager.submit_task(
_tasks.NovaLimitsGet(tenant_id=proj.id))
return self._normalize_limits(limits)

View File

@ -23,11 +23,20 @@ from shade.tests.functional import base
class TestUsage(base.BaseFunctionalTestCase):
def test_get_limits(self):
def test_get_our_limits(self):
'''Test quotas functionality'''
limits = self.operator_cloud.get_limits('demo')
limits = self.demo_cloud.get_compute_limits()
self.assertIsNotNone(limits)
self.assertTrue(hasattr(limits, 'rate'))
self.assertTrue(hasattr(limits, 'max_server_meta'))
# Test normalize limits
self.assertFalse(hasattr(limits, 'HUMAN_ID'))
self.assertFalse(hasattr(limits, 'maxImageMeta'))
def test_get_other_limits(self):
'''Test quotas functionality'''
limits = self.operator_cloud.get_compute_limits('demo')
self.assertIsNotNone(limits)
self.assertTrue(hasattr(limits, 'max_server_meta'))
# Test normalize limits
self.assertFalse(hasattr(limits, 'maxImageMeta'))

View File

@ -20,11 +20,17 @@ from shade.tests import fakes
class TestLimits(base.TestCase):
@mock.patch.object(shade.OpenStackCloud, 'nova_client')
def test_get_compute_limits(self, mock_nova):
self.cloud.get_compute_limits()
mock_nova.limits.get.assert_called_once_with()
@mock.patch.object(shade.OpenStackCloud, 'nova_client')
@mock.patch.object(shade.OpenStackCloud, 'keystone_client')
def test_get_limits(self, mock_keystone, mock_nova):
def test_other_get_compute_limits(self, mock_keystone, mock_nova):
project = fakes.FakeProject('project_a')
mock_keystone.tenants.list.return_value = [project]
self.op_cloud.get_limits(project)
self.op_cloud.get_compute_limits(project)
mock_nova.limits.get.assert_called_once_with(tenant_id='project_a')