Add support for registered limits

This change add client support for creating, reading, updating, and
deleting registered limits.

A subsequent patch will do the same for project-specific limits.

bp unified-limits
Depends-On: https://review.openstack.org/#/c/569741/
Change-Id: I6b5d106d08af53c2ad41ed3f799e9e71d370c6dd
This commit is contained in:
Lance Bragstad 2018-01-24 21:46:52 +00:00
parent 20a2f2ffdc
commit 0b9a7b05c0
4 changed files with 248 additions and 0 deletions

View File

@ -0,0 +1,76 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from keystoneclient.tests.unit.v3 import utils
from keystoneclient.v3 import registered_limits
class RegisteredLimitTests(utils.ClientTestCase, utils.CrudTests):
def setUp(self):
super(RegisteredLimitTests, self).setUp()
self.key = 'registered_limit'
self.collection_key = 'registered_limits'
self.model = registered_limits.RegisteredLimit
self.manager = self.client.registered_limits
def new_ref(self, **kwargs):
ref = {
'id': uuid.uuid4().hex,
'service_id': uuid.uuid4().hex,
'resource_name': uuid.uuid4().hex,
'default_limit': 10,
'description': uuid.uuid4().hex
}
ref.update(kwargs)
return ref
def test_create(self):
# This test overrides the generic test case provided by the CrudTests
# class because the registered limits API supports creating multiple
# limits in a single POST request. As a result, it returns the
# registered limits as a list of all the created limits from the
# request. This is different from what the base test_create() method
# assumes about keystone's API. The changes here override the base test
# to closely model how the actual registered limit API behaves.
ref = self.new_ref()
manager_ref = ref.copy()
manager_ref.pop('id')
req_ref = [manager_ref.copy()]
self.stub_entity('POST', entity=req_ref, status_code=201)
returned = self.manager.create(**utils.parameterize(manager_ref))
self.assertIsInstance(returned, self.model)
expected_limit = req_ref.pop()
for attr in expected_limit:
self.assertEqual(
getattr(returned, attr),
expected_limit[attr],
'Expected different %s' % attr)
self.assertEntityRequestBodyIs([expected_limit])
def test_list_filter_by_service(self):
service_id = uuid.uuid4().hex
expected_query = {'service_id': service_id}
self.test_list(expected_query=expected_query, service=service_id)
def test_list_filter_resource_name(self):
resource_name = uuid.uuid4().hex
self.test_list(resource_name=resource_name)
def test_list_filter_region(self):
region_id = uuid.uuid4().hex
expected_query = {'region_id': region_id}
self.test_list(expected_query=expected_query, region=region_id)

View File

@ -40,6 +40,7 @@ from keystoneclient.v3 import groups
from keystoneclient.v3 import policies from keystoneclient.v3 import policies
from keystoneclient.v3 import projects from keystoneclient.v3 import projects
from keystoneclient.v3 import regions from keystoneclient.v3 import regions
from keystoneclient.v3 import registered_limits
from keystoneclient.v3 import role_assignments from keystoneclient.v3 import role_assignments
from keystoneclient.v3 import roles from keystoneclient.v3 import roles
from keystoneclient.v3 import services from keystoneclient.v3 import services
@ -170,6 +171,10 @@ class Client(httpclient.HTTPClient):
:py:class:`keystoneclient.v3.regions.RegionManager` :py:class:`keystoneclient.v3.regions.RegionManager`
.. py:attribute:: registered_limits
:py:class:`keystoneclient.v3.registered_limits.RegisteredLimitManager`
.. py:attribute:: role_assignments .. py:attribute:: role_assignments
:py:class:`keystoneclient.v3.role_assignments.RoleAssignmentManager` :py:class:`keystoneclient.v3.role_assignments.RoleAssignmentManager`
@ -233,6 +238,8 @@ class Client(httpclient.HTTPClient):
self.oauth1 = oauth1.create_oauth_manager(self._adapter) self.oauth1 = oauth1.create_oauth_manager(self._adapter)
self.policies = policies.PolicyManager(self._adapter) self.policies = policies.PolicyManager(self._adapter)
self.projects = projects.ProjectManager(self._adapter) self.projects = projects.ProjectManager(self._adapter)
self.registered_limits = registered_limits.RegisteredLimitManager(
self._adapter)
self.regions = regions.RegionManager(self._adapter) self.regions = regions.RegionManager(self._adapter)
self.role_assignments = ( self.role_assignments = (
role_assignments.RoleAssignmentManager(self._adapter)) role_assignments.RoleAssignmentManager(self._adapter))

View File

@ -0,0 +1,158 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from keystoneclient import base
class RegisteredLimit(base.Resource):
"""Represents a registered limit.
Attributes:
* id: a UUID that identifies the registered limit
* service_id: a UUID that identifies the service for the limit
* region_id: a UUID that identifies the region for the limit
* resource_name: the name of the resource to limit
* default_limit: the default limit for projects to assume
* description: a description of the registered limit
"""
pass
class RegisteredLimitManager(base.CrudManager):
"""Manager class for registered limits."""
resource_class = RegisteredLimit
collection_key = 'registered_limits'
key = 'registered_limit'
def create(self, service, resource_name, default_limit,
description=None, region=None, **kwargs):
"""Create a registered limit.
:param service: a UUID that identifies the service for the limit.
:type service: str
:param resource_name: the name of the resource to limit.
:type resource_name: str
:param default_limit: the default limit for projects to assume.
:type default_limit: int
:param description: a string that describes the limit
:type description: str
:param region: a UUID that identifies the region for the limit.
:type region: str
:returns: a reference of the created registered limit.
:rtype: :class:`keystoneclient.v3.registered_limits.RegisteredLimit`
"""
# NOTE(lbragstad): Keystone's registered limit API supports creation of
# limits in batches. This client accepts a single limit and passes it
# to the identity service as a list of a single item.
limit_data = base.filter_none(
service_id=base.getid(service),
resource_name=resource_name,
default_limit=default_limit,
description=description,
region_id=base.getid(region),
**kwargs
)
body = {self.collection_key: [limit_data]}
resp, body = self.client.post('/registered_limits', body=body)
registered_limit = body[self.collection_key].pop()
return self.resource_class(self, registered_limit)
def update(self, registered_limit, service=None, resource_name=None,
default_limit=None, description=None, region=None, **kwargs):
"""Update a registered limit.
:param registered_limit:
the UUID or reference of the registered limit to update.
:param registered_limit:
str or :class:`keystoneclient.v3.registered_limits.RegisteredLimit`
:param service: a UUID that identifies the service for the limit.
:type service: str
:param resource_name: the name of the resource to limit.
:type resource_name: str
:param default_limit: the default limit for projects to assume.
:type defaut slt_limit: int
:param description: a string that describes the limit
:type description: str
:param region: a UUID that identifies the region for the limit.
:type region: str
:returns: a reference of the updated registered limit.
:rtype: :class:`keystoneclient.v3.registered_limits.RegisteredLimit`
"""
return super(RegisteredLimitManager, self).update(
registered_limit_id=base.getid(registered_limit),
service_id=base.getid(service),
resource_name=resource_name,
default_limit=default_limit,
description=description,
region=region,
**kwargs
)
def get(self, registered_limit):
"""Retrieve a registered limit.
:param registered_limit: the registered limit to get.
:type registered_limit:
str or :class:`keystoneclient.v3.registered_limits.RegisteredLimit`
:returns: a specific registered limit.
:rtype: :class:`keystoneclient.v3.registered_limits.RegisteredLimit`
"""
return super(RegisteredLimitManager, self).get(
registered_limit_id=base.getid(registered_limit))
def list(self, service=None, resource_name=None, region=None, **kwargs):
"""List registered limits.
Any parameter provided will be passed to the server as a filter.
:param service: filter registered limits by service
:type service: a UUID or :class:`keystoneclient.v3.services.Service`
:param resource_name: filter registered limits by resource name
:type resource_name: str
:param region: filter registered limits by region
:type region: a UUID or :class:`keystoneclient.v3.regions.Region`
:returns: a list of registered limits.
:rtype: list of
:class:`keystoneclient.v3.registered_limits.RegisteredLimit`
"""
return super(RegisteredLimitManager, self).list(
service_id=base.getid(service),
resource_name=resource_name,
region_id=base.getid(region),
**kwargs)
def delete(self, registered_limit):
"""Delete a registered limit.
:param registered_limit: the registered limit to delete.
:type registered_limit:
str or :class:`keystoneclient.v3.registered_limits.RegisteredLimit`
:returns: Response object with 204 status.
:rtype: :class:`requests.models.Response`
"""
registered_limit_id = base.getid(registered_limit)
return super(RegisteredLimitManager, self).delete(
registered_limit_id=registered_limit_id
)

View File

@ -0,0 +1,7 @@
---
features:
- |
Added support for managing registered limits. The ``POST`` API for
registered limits in keystone supports batch creation, but the client
implementation does not. Creation of registered limits using the client
must be done one at a time.