compute, block storage: Minor fixes to limits

Add a proper RateLimit class for compute (even though this is no longer
a thing starting in Newton) and use consistent naming across services.

Change-Id: Ib8a926900dca77cf48492839664bf2c5c13aab70
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2024-05-08 11:47:57 +01:00
parent 6328a8fb2f
commit 916f9af658
13 changed files with 75 additions and 38 deletions

View File

@ -12,12 +12,12 @@ The ``AbsoluteLimit`` class inherits from
.. autoclass:: openstack.block_storage.v2.limits.AbsoluteLimit .. autoclass:: openstack.block_storage.v2.limits.AbsoluteLimit
:members: :members:
The Limit Class The Limits Class
--------------- ----------------
The ``Limit`` class inherits from :class:`~openstack.resource.Resource`. The ``Limit`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.block_storage.v2.limits.Limit .. autoclass:: openstack.block_storage.v2.limits.Limits
:members: :members:
The RateLimit Class The RateLimit Class

View File

@ -12,12 +12,12 @@ The ``AbsoluteLimit`` class inherits from
.. autoclass:: openstack.block_storage.v3.limits.AbsoluteLimit .. autoclass:: openstack.block_storage.v3.limits.AbsoluteLimit
:members: :members:
The Limit Class The Limits Class
--------------- ----------------
The ``Limit`` class inherits from :class:`~openstack.resource.Resource`. The ``Limits`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.block_storage.v3.limits.Limit .. autoclass:: openstack.block_storage.v3.limits.Limits
:members: :members:
The RateLimit Class The RateLimit Class

View File

@ -651,15 +651,15 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
:param project: A project to get limits for. The value can be either :param project: A project to get limits for. The value can be either
the ID of a project or an the ID of a project or an
:class:`~openstack.identity.v2.project.Project` instance. :class:`~openstack.identity.v2.project.Project` instance.
:returns: A Limit object, including both :returns: A Limits object, including both
:class:`~openstack.block_storage.v2.limits.AbsoluteLimit` and :class:`~openstack.block_storage.v2.limits.AbsoluteLimit` and
:class:`~openstack.block_storage.v2.limits.RateLimit` :class:`~openstack.block_storage.v2.limits.RateLimit`
:rtype: :class:`~openstack.block_storage.v2.limits.Limit` :rtype: :class:`~openstack.block_storage.v2.limits.Limits`
""" """
params = {} params = {}
if project: if project:
params['project_id'] = resource.Resource._get_id(project) params['project_id'] = resource.Resource._get_id(project)
return self._get(_limits.Limit, requires_id=False, **params) return self._get(_limits.Limits, requires_id=False, **params)
# ====== CAPABILITIES ====== # ====== CAPABILITIES ======
def get_capabilities(self, host): def get_capabilities(self, host):

View File

@ -67,7 +67,7 @@ class RateLimits(resource.Resource):
uri = resource.Body("uri") uri = resource.Body("uri")
class Limit(resource.Resource): class Limits(resource.Resource):
resource_key = "limits" resource_key = "limits"
base_path = "/limits" base_path = "/limits"
@ -80,3 +80,7 @@ class Limit(resource.Resource):
#: Rate-limit volume copy bandwidth, used to mitigate #: Rate-limit volume copy bandwidth, used to mitigate
#: slow down of data access from the instances. #: slow down of data access from the instances.
rate = resource.Body("rate", type=list, list_type=RateLimits) rate = resource.Body("rate", type=list, list_type=RateLimits)
# legacy alias
Limit = Limits

View File

@ -47,7 +47,7 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"group": _group.Group, "group": _group.Group,
"group_snapshot": _group_snapshot.GroupSnapshot, "group_snapshot": _group_snapshot.GroupSnapshot,
"group_type": _group_type.GroupType, "group_type": _group_type.GroupType,
"limits": _limits.Limit, "limits": _limits.Limits,
"quota_set": _quota_set.QuotaSet, "quota_set": _quota_set.QuotaSet,
"resource_filter": _resource_filter.ResourceFilter, "resource_filter": _resource_filter.ResourceFilter,
"snapshot": _snapshot.Snapshot, "snapshot": _snapshot.Snapshot,
@ -1282,15 +1282,15 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
:param project: A project to get limits for. The value can be either :param project: A project to get limits for. The value can be either
the ID of a project or an the ID of a project or an
:class:`~openstack.identity.v3.project.Project` instance. :class:`~openstack.identity.v3.project.Project` instance.
:returns: A Limit object, including both :returns: A Limits object, including both
:class:`~openstack.block_storage.v3.limits.AbsoluteLimit` and :class:`~openstack.block_storage.v3.limits.AbsoluteLimit` and
:class:`~openstack.block_storage.v3.limits.RateLimit` :class:`~openstack.block_storage.v3.limits.RateLimit`
:rtype: :class:`~openstack.block_storage.v3.limits.Limit` :rtype: :class:`~openstack.block_storage.v3.limits.Limits`
""" """
params = {} params = {}
if project: if project:
params['project_id'] = resource.Resource._get_id(project) params['project_id'] = resource.Resource._get_id(project)
return self._get(_limits.Limit, requires_id=False, **params) return self._get(_limits.Limits, requires_id=False, **params)
# ====== CAPABILITIES ====== # ====== CAPABILITIES ======
def get_capabilities(self, host): def get_capabilities(self, host):

View File

@ -14,7 +14,7 @@ from openstack import resource
class AbsoluteLimit(resource.Resource): class AbsoluteLimit(resource.Resource):
#: Properties # Properties
#: The maximum total amount of backups, in gibibytes (GiB). #: The maximum total amount of backups, in gibibytes (GiB).
max_total_backup_gigabytes = resource.Body( max_total_backup_gigabytes = resource.Body(
"maxTotalBackupGigabytes", type=int "maxTotalBackupGigabytes", type=int
@ -44,7 +44,7 @@ class AbsoluteLimit(resource.Resource):
class RateLimit(resource.Resource): class RateLimit(resource.Resource):
#: Properties # Properties
#: Rate limits next availabe time. #: Rate limits next availabe time.
next_available = resource.Body("next-available") next_available = resource.Body("next-available")
#: Integer for rate limits remaining. #: Integer for rate limits remaining.
@ -58,7 +58,7 @@ class RateLimit(resource.Resource):
class RateLimits(resource.Resource): class RateLimits(resource.Resource):
#: Properties # Properties
#: A list of the specific limits that apply to the ``regex`` and ``uri``. #: A list of the specific limits that apply to the ``regex`` and ``uri``.
limits = resource.Body("limit", type=list, list_type=RateLimit) limits = resource.Body("limit", type=list, list_type=RateLimit)
#: A regex representing which routes this rate limit applies to. #: A regex representing which routes this rate limit applies to.
@ -67,16 +67,20 @@ class RateLimits(resource.Resource):
uri = resource.Body("uri") uri = resource.Body("uri")
class Limit(resource.Resource): class Limits(resource.Resource):
resource_key = "limits" resource_key = "limits"
base_path = "/limits" base_path = "/limits"
# capabilities # capabilities
allow_fetch = True allow_fetch = True
#: Properties # Properties
#: An absolute limits object. #: An absolute limits object.
absolute = resource.Body("absolute", type=AbsoluteLimit) absolute = resource.Body("absolute", type=AbsoluteLimit)
#: Rate-limit volume copy bandwidth, used to mitigate #: Rate-limit volume copy bandwidth, used to mitigate
#: slow down of data access from the instances. #: slow down of data access from the instances.
rate = resource.Body("rate", type=list, list_type=RateLimits) rate = resource.Body("rate", type=list, list_type=RateLimits)
# Legacy alias
Limit = Limits

View File

@ -269,7 +269,7 @@ class BlockStorageCloudMixin:
:param name_or_id: (optional) Project name or ID to get limits for :param name_or_id: (optional) Project name or ID to get limits for
if different from the current project if different from the current project
:returns: The volume ``Limit`` object if found, else None. :returns: The volume ``Limits`` object if found, else None.
""" """
params = {} params = {}
if name_or_id: if name_or_id:

View File

@ -16,6 +16,7 @@ from openstack import resource
class AbsoluteLimits(resource.Resource): class AbsoluteLimits(resource.Resource):
_max_microversion = '2.57' _max_microversion = '2.57'
# Properties
#: The number of key-value pairs that can be set as image metadata. #: The number of key-value pairs that can be set as image metadata.
image_meta = resource.Body("maxImageMeta", aka="max_image_meta") image_meta = resource.Body("maxImageMeta", aka="max_image_meta")
#: The maximum number of personality contents that can be supplied. #: The maximum number of personality contents that can be supplied.
@ -73,10 +74,23 @@ class AbsoluteLimits(resource.Resource):
class RateLimit(resource.Resource): class RateLimit(resource.Resource):
# TODO(mordred) Make a resource type for the contents of limit and add # Properties
# it to list_type here. #: Rate limits next availabe time.
next_available = resource.Body("next-available")
#: Integer for rate limits remaining.
remaining = resource.Body("remaining", type=int)
#: Unit of measurement for the value parameter.
unit = resource.Body("unit")
#: Integer number of requests which can be made.
value = resource.Body("value", type=int)
#: An HTTP verb (POST, PUT, etc.).
verb = resource.Body("verb")
class RateLimits(resource.Resource):
# Properties
#: A list of the specific limits that apply to the ``regex`` and ``uri``. #: A list of the specific limits that apply to the ``regex`` and ``uri``.
limits = resource.Body("limit", type=list) limits = resource.Body("limit", type=list, list_type=RateLimit)
#: A regex representing which routes this rate limit applies to. #: A regex representing which routes this rate limit applies to.
regex = resource.Body("regex") regex = resource.Body("regex")
#: A URI representing which routes this rate limit applies to. #: A URI representing which routes this rate limit applies to.
@ -89,10 +103,19 @@ class Limits(resource.Resource):
allow_fetch = True allow_fetch = True
_query_mapping = resource.QueryParameters('tenant_id') _query_mapping = resource.QueryParameters(
'tenant_id',
'reserved',
project_id='tenant_id',
)
# Properties
#: An absolute limits object.
absolute = resource.Body("absolute", type=AbsoluteLimits) absolute = resource.Body("absolute", type=AbsoluteLimits)
rate = resource.Body("rate", type=list, list_type=RateLimit) #: Rate-limit compute resources. This is only populated when using the
#: legacy v2 API which was removed in Nova 14.0.0 (Newton). In v2.1 it will
#: always be an empty list.
rate = resource.Body("rate", type=list, list_type=RateLimits)
def fetch( def fetch(
self, self,

View File

@ -146,7 +146,7 @@ class TestRateLimits(base.TestCase):
class TestLimit(base.TestCase): class TestLimit(base.TestCase):
def test_basic(self): def test_basic(self):
limit_resource = limits.Limit() limit_resource = limits.Limits()
self.assertEqual('limits', limit_resource.resource_key) self.assertEqual('limits', limit_resource.resource_key)
self.assertEqual('/limits', limit_resource.base_path) self.assertEqual('/limits', limit_resource.base_path)
self.assertTrue(limit_resource.allow_fetch) self.assertTrue(limit_resource.allow_fetch)
@ -201,6 +201,6 @@ class TestLimit(base.TestCase):
self._test_rate_limit(expected[0]['limit'], actual[0].limits) self._test_rate_limit(expected[0]['limit'], actual[0].limits)
def test_make_limit(self): def test_make_limit(self):
limit_resource = limits.Limit(**LIMIT) limit_resource = limits.Limits(**LIMIT)
self._test_rate_limits(LIMIT['rate'], limit_resource.rate) self._test_rate_limits(LIMIT['rate'], limit_resource.rate)
self._test_absolute_limit(LIMIT['absolute'], limit_resource.absolute) self._test_absolute_limit(LIMIT['absolute'], limit_resource.absolute)

View File

@ -321,7 +321,7 @@ class TestLimit(TestVolumeProxy):
def test_limits_get(self): def test_limits_get(self):
self.verify_get( self.verify_get(
self.proxy.get_limits, self.proxy.get_limits,
limits.Limit, limits.Limits,
method_args=[], method_args=[],
expected_kwargs={'requires_id': False}, expected_kwargs={'requires_id': False},
) )

View File

@ -146,7 +146,7 @@ class TestRateLimits(base.TestCase):
class TestLimit(base.TestCase): class TestLimit(base.TestCase):
def test_basic(self): def test_basic(self):
limit_resource = limits.Limit() limit_resource = limits.Limits()
self.assertEqual('limits', limit_resource.resource_key) self.assertEqual('limits', limit_resource.resource_key)
self.assertEqual('/limits', limit_resource.base_path) self.assertEqual('/limits', limit_resource.base_path)
self.assertTrue(limit_resource.allow_fetch) self.assertTrue(limit_resource.allow_fetch)
@ -201,6 +201,6 @@ class TestLimit(base.TestCase):
self._test_rate_limit(expected[0]['limit'], actual[0].limits) self._test_rate_limit(expected[0]['limit'], actual[0].limits)
def test_make_limit(self): def test_make_limit(self):
limit_resource = limits.Limit(**LIMIT) limit_resource = limits.Limits(**LIMIT)
self._test_rate_limits(LIMIT['rate'], limit_resource.rate) self._test_rate_limits(LIMIT['rate'], limit_resource.rate)
self._test_absolute_limit(LIMIT['absolute'], limit_resource.absolute) self._test_absolute_limit(LIMIT['absolute'], limit_resource.absolute)

View File

@ -137,7 +137,7 @@ class TestLimit(TestVolumeProxy):
def test_limits_get(self): def test_limits_get(self):
self.verify_get( self.verify_get(
self.proxy.get_limits, self.proxy.get_limits,
limits.Limit, limits.Limits,
method_args=[], method_args=[],
expected_kwargs={'requires_id': False}, expected_kwargs={'requires_id': False},
) )

View File

@ -107,9 +107,9 @@ class TestAbsoluteLimits(base.TestCase):
) )
class TestRateLimit(base.TestCase): class TestRateLimits(base.TestCase):
def test_basic(self): def test_basic(self):
sot = limits.RateLimit() sot = limits.RateLimits()
self.assertIsNone(sot.resource_key) self.assertIsNone(sot.resource_key)
self.assertIsNone(sot.resources_key) self.assertIsNone(sot.resources_key)
self.assertEqual("", sot.base_path) self.assertEqual("", sot.base_path)
@ -120,10 +120,10 @@ class TestRateLimit(base.TestCase):
self.assertFalse(sot.allow_list) self.assertFalse(sot.allow_list)
def test_make_it(self): def test_make_it(self):
sot = limits.RateLimit(**RATE_LIMIT) sot = limits.RateLimits(**RATE_LIMIT)
self.assertEqual(RATE_LIMIT["regex"], sot.regex) self.assertEqual(RATE_LIMIT["regex"], sot.regex)
self.assertEqual(RATE_LIMIT["uri"], sot.uri) self.assertEqual(RATE_LIMIT["uri"], sot.uri)
self.assertEqual(RATE_LIMIT["limit"], sot.limits) self.assertIsInstance(sot.limits[0], limits.RateLimit)
class TestLimits(base.TestCase): class TestLimits(base.TestCase):
@ -137,7 +137,13 @@ class TestLimits(base.TestCase):
self.assertFalse(sot.allow_delete) self.assertFalse(sot.allow_delete)
self.assertFalse(sot.allow_list) self.assertFalse(sot.allow_list)
self.assertDictEqual( self.assertDictEqual(
{'limit': 'limit', 'marker': 'marker', 'tenant_id': 'tenant_id'}, {
'limit': 'limit',
'marker': 'marker',
'tenant_id': 'tenant_id',
'project_id': 'tenant_id',
'reserved': 'reserved',
},
sot._query_mapping._mapping, sot._query_mapping._mapping,
) )
@ -211,7 +217,7 @@ class TestLimits(base.TestCase):
self.assertEqual(RATE_LIMIT["uri"], sot.rate[0].uri) self.assertEqual(RATE_LIMIT["uri"], sot.rate[0].uri)
self.assertEqual(RATE_LIMIT["regex"], sot.rate[0].regex) self.assertEqual(RATE_LIMIT["regex"], sot.rate[0].regex)
self.assertEqual(RATE_LIMIT["limit"], sot.rate[0].limits) self.assertIsInstance(sot.rate[0].limits[0], limits.RateLimit)
dsot = sot.to_dict() dsot = sot.to_dict()