Merge "Add support for project-specific limits"
This commit is contained in:
commit
234ea50d5d
|
@ -0,0 +1,77 @@
|
|||
# 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 limits
|
||||
|
||||
|
||||
class LimitTests(utils.ClientTestCase, utils.CrudTests):
|
||||
def setUp(self):
|
||||
super(LimitTests, self).setUp()
|
||||
self.key = 'limit'
|
||||
self.collection_key = 'limits'
|
||||
self.model = limits.Limit
|
||||
self.manager = self.client.limits
|
||||
|
||||
def new_ref(self, **kwargs):
|
||||
ref = {
|
||||
'id': uuid.uuid4().hex,
|
||||
'project_id': uuid.uuid4().hex,
|
||||
'service_id': uuid.uuid4().hex,
|
||||
'resource_name': uuid.uuid4().hex,
|
||||
'resource_limit': 15,
|
||||
'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 limits API supports creating multiple limits in a
|
||||
# single POST request. As a result, it returns the 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
|
||||
# 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_filtered_by_resource_name(self):
|
||||
resource_name = uuid.uuid4().hex
|
||||
self.test_list(resource_name=resource_name)
|
||||
|
||||
def test_list_filtered_by_region(self):
|
||||
region_id = uuid.uuid4().hex
|
||||
expected_query = {'region_id': region_id}
|
||||
self.test_list(expected_query=expected_query, region=region_id)
|
|
@ -37,6 +37,7 @@ from keystoneclient.v3 import ec2
|
|||
from keystoneclient.v3 import endpoint_groups
|
||||
from keystoneclient.v3 import endpoints
|
||||
from keystoneclient.v3 import groups
|
||||
from keystoneclient.v3 import limits
|
||||
from keystoneclient.v3 import policies
|
||||
from keystoneclient.v3 import projects
|
||||
from keystoneclient.v3 import regions
|
||||
|
@ -159,6 +160,10 @@ class Client(httpclient.HTTPClient):
|
|||
|
||||
:py:class:`keystoneclient.v3.groups.GroupManager`
|
||||
|
||||
.. py:attribute:: limits
|
||||
|
||||
:py:class:`keystoneclient.v3.limits.LimitManager`
|
||||
|
||||
.. py:attribute:: oauth1
|
||||
|
||||
:py:class:`keystoneclient.v3.contrib.oauth1.core.OAuthManager`
|
||||
|
@ -235,6 +240,7 @@ class Client(httpclient.HTTPClient):
|
|||
self.domains = domains.DomainManager(self._adapter)
|
||||
self.federation = federation.FederationManager(self._adapter)
|
||||
self.groups = groups.GroupManager(self._adapter)
|
||||
self.limits = limits.LimitManager(self._adapter)
|
||||
self.oauth1 = oauth1.create_oauth_manager(self._adapter)
|
||||
self.policies = policies.PolicyManager(self._adapter)
|
||||
self.projects = projects.ProjectManager(self._adapter)
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
# 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 Limit(base.Resource):
|
||||
"""Represents a project limit.
|
||||
|
||||
Attributes:
|
||||
* id: a UUID that identifies the project limit
|
||||
* service_id: a UUID that identifies the service for the limit
|
||||
* region_id: a UUID that identifies the region for the limit
|
||||
* project_id: a UUID that identifies the project for the limit
|
||||
* resource_name: the name of the resource to limit
|
||||
* resource_limit: the limit to apply to the project
|
||||
* description: a description for the project limit
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class LimitManager(base.CrudManager):
|
||||
"""Manager class for project limits."""
|
||||
|
||||
resource_class = Limit
|
||||
collection_key = 'limits'
|
||||
key = 'limit'
|
||||
|
||||
def create(self, project, service, resource_name, resource_limit,
|
||||
description=None, region=None, **kwargs):
|
||||
"""Create a project-specific limit.
|
||||
|
||||
:param project: the project to create a limit for.
|
||||
:type project: str or :class:`keystoneclient.v3.projects.Project`
|
||||
:param service: the service that owns the resource to limit.
|
||||
:type service: str or :class:`keystoneclient.v3.services.Service`
|
||||
:param resource_name: the name of the resource to limit
|
||||
:type resource_name: str
|
||||
:param resource_limit: the quantity of the limit
|
||||
:type resource_limit: int
|
||||
:param description: a description of the limit
|
||||
:type description: str
|
||||
:param region: region the limit applies to
|
||||
:type region: str or :class:`keystoneclient.v3.regions.Region`
|
||||
|
||||
:returns: a reference of the created limit
|
||||
:rtype: :class:`keystoneclient.v3.limits.Limit`
|
||||
|
||||
"""
|
||||
limit_data = base.filter_none(
|
||||
project_id=base.getid(project),
|
||||
service_id=base.getid(service),
|
||||
resource_name=resource_name,
|
||||
resource_limit=resource_limit,
|
||||
description=description,
|
||||
region_id=base.getid(region),
|
||||
**kwargs
|
||||
)
|
||||
body = {self.collection_key: [limit_data]}
|
||||
resp, body = self.client.post('/limits', body=body)
|
||||
limit = body[self.collection_key].pop()
|
||||
return self.resource_class(self, limit)
|
||||
|
||||
def update(self, limit, project=None, service=None, resource_name=None,
|
||||
resource_limit=None, description=None, **kwargs):
|
||||
"""Update a project-specific limit.
|
||||
|
||||
:param limit: a limit to update
|
||||
:param project: the project ID of the limit to update
|
||||
:type project: str or :class:`keystoneclient.v3.projects.Project`
|
||||
:param resource_limit: the limit of the limit's resource to update
|
||||
:type: resource_limit: int
|
||||
:param description: a description of the limit
|
||||
:type description: str
|
||||
|
||||
:returns: a reference of the updated limit.
|
||||
:rtype: :class:`keystoneclient.v3.limits.Limit`
|
||||
|
||||
"""
|
||||
return super(LimitManager, self).update(
|
||||
limit_id=base.getid(limit),
|
||||
project_id=base.getid(project),
|
||||
service_id=base.getid(service),
|
||||
resource_name=resource_name,
|
||||
resource_limit=resource_limit,
|
||||
description=description,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def get(self, limit):
|
||||
"""Retrieve a project limit.
|
||||
|
||||
:param limit:
|
||||
the project-specific limit to be retrieved.
|
||||
:type limit:
|
||||
str or :class:`keystoneclient.v3.limit.Limit`
|
||||
|
||||
:returns: a project-specific limit
|
||||
:rtype: :class:`keystoneclient.v3.limit.Limit`
|
||||
|
||||
"""
|
||||
return super(LimitManager, self).get(limit_id=base.getid(limit))
|
||||
|
||||
def list(self, service=None, region=None, resource_name=None, **kwargs):
|
||||
"""List project-specific limits.
|
||||
|
||||
Any parameter provided will be passed to the server as a filter
|
||||
|
||||
:param service: service to filter limits by
|
||||
:type service: UUID or :class:`keystoneclient.v3.services.Service`
|
||||
:param region: region to filter limits by
|
||||
:type region: UUID or :class:`keystoneclient.v3.regions.Region`
|
||||
:param resource_name: the name of the resource to filter limits by
|
||||
:type resource_name: str
|
||||
|
||||
:returns: a list of project-specific limits.
|
||||
:rtype: list of :class:`keystoneclient.v3.limits.Limit`
|
||||
|
||||
"""
|
||||
return super(LimitManager, self).list(
|
||||
service_id=base.getid(service),
|
||||
region_id=base.getid(region),
|
||||
resource_name=resource_name,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def delete(self, limit):
|
||||
"""Delete a project-specific limit.
|
||||
|
||||
:param limit: the project-specific limit to be deleted.
|
||||
:type limit: str or :class:`keystoneclient.v3.limit.Limit`
|
||||
|
||||
:returns: Response object with 204 status
|
||||
:rtype: :class:`requests.models.Response`
|
||||
|
||||
"""
|
||||
return super(LimitManager, self).delete(limit_id=base.getid(limit))
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Added support for managing project-specific limits. The ``POST`` API for
|
||||
limits in keystone supports batch creation, but the client implementation
|
||||
does not. Creation for limits using the client must be done one at a time.
|
Loading…
Reference in New Issue