Introduce QuotaSet in the compute service

Start using newly introduced QuotaSet base resource in the compute area.

Change-Id: I3165dd717035319c713a94326bd964fc63e2acf7
This commit is contained in:
Artem Goncharov 2021-05-18 17:21:55 +02:00 committed by Artem Goncharov
parent 94cb864d86
commit b7ebc731ca
8 changed files with 281 additions and 0 deletions

View File

@ -149,3 +149,10 @@ Extension Operations
.. autoclass:: openstack.compute.v2._proxy.Proxy .. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex: :noindex:
:members: find_extension, extensions :members: find_extension, extensions
QuotaSet Operations
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex:
:members: get_quota_set, get_quota_set_defaults,
revert_quota_set, update_quota_set

View File

@ -13,3 +13,4 @@ Compute Resources
v2/server_interface v2/server_interface
v2/server_ip v2/server_ip
v2/hypervisor v2/hypervisor
v2/quota_set

View File

@ -0,0 +1,12 @@
openstack.compute.v2.quota_set
==============================
.. automodule:: openstack.compute.v2.quota_set
The QuotaSet Class
------------------
The ``QuotaSet`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.compute.v2.quota_set.QuotaSet
:members:

View File

@ -20,6 +20,7 @@ from openstack.compute.v2 import hypervisor as _hypervisor
from openstack.compute.v2 import image as _image from openstack.compute.v2 import image as _image
from openstack.compute.v2 import keypair as _keypair from openstack.compute.v2 import keypair as _keypair
from openstack.compute.v2 import limits from openstack.compute.v2 import limits
from openstack.compute.v2 import quota_set as _quota_set
from openstack.compute.v2 import server as _server from openstack.compute.v2 import server as _server
from openstack.compute.v2 import server_diagnostics as _server_diagnostics from openstack.compute.v2 import server_diagnostics as _server_diagnostics
from openstack.compute.v2 import server_group as _server_group from openstack.compute.v2 import server_group as _server_group
@ -29,6 +30,7 @@ from openstack.compute.v2 import server_remote_console as _src
from openstack.compute.v2 import service as _service from openstack.compute.v2 import service as _service
from openstack.compute.v2 import volume_attachment as _volume_attachment from openstack.compute.v2 import volume_attachment as _volume_attachment
from openstack import exceptions from openstack import exceptions
from openstack.identity.v3 import project as _project
from openstack.network.v2 import security_group as _sg from openstack.network.v2 import security_group as _sg
from openstack import proxy from openstack import proxy
from openstack import resource from openstack import resource
@ -1818,6 +1820,74 @@ class Proxy(proxy.Proxy):
else: else:
return server.get_console_url(self, console_type) return server.get_console_url(self, console_type)
def get_quota_set(self, project, usage=False, **query):
"""Show QuotaSet information for the project
:param project: ID or instance of
:class:`~openstack.identity.project.Project` of the project for
which the quota should be retrieved
:param bool usage: When set to ``True`` quota usage and reservations
would be filled.
:param dict query: Additional query parameters to use.
:returns: One :class:`~openstack.compute.v2.quota_set.QuotaSet`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
project = self._get_resource(_project.Project, project)
res = self._get_resource(
_quota_set.QuotaSet, None, project_id=project.id)
return res.fetch(
self, usage=usage, **query)
def get_quota_set_defaults(self, project):
"""Show QuotaSet defaults for the project
:param project: ID or instance of
:class:`~openstack.identity.project.Project` of the project for
which the quota should be retrieved
:returns: One :class:`~openstack.compute.v2.quota_set.QuotaSet`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
project = self._get_resource(_project.Project, project)
res = self._get_resource(
_quota_set.QuotaSet, None, project_id=project.id)
return res.fetch(
self, base_path='/os-quota-sets/defaults')
def revert_quota_set(self, project, **query):
"""Reset Quota for the project/user.
:param project: ID or instance of
:class:`~openstack.identity.project.Project` of the project for
which the quota should be resetted.
:param dict query: Additional parameters to be used.
:returns: ``None``
"""
project = self._get_resource(_project.Project, project)
res = self._get_resource(
_quota_set.QuotaSet, None, project_id=project.id)
return res.delete(self, **query)
def update_quota_set(self, quota_set, query=None, **attrs):
"""Update a QuotaSet.
:param quota_set: Either the ID of a quota_set or a
:class:`~openstack.compute.v2.quota_set.QuotaSet` instance.
:param dict query: Optional parameters to be used with update call.
:attrs kwargs: The attributes to update on the QuotaSet represented
by ``quota_set``.
:returns: The updated QuotaSet
:rtype: :class:`~openstack.compute.v2.quota_set.QuotaSet`
"""
res = self._get_resource(_quota_set.QuotaSet, quota_set, **attrs)
return res.commit(self, **query)
def _get_cleanup_dependencies(self): def _get_cleanup_dependencies(self):
return { return {
'compute': { 'compute': {

View File

@ -0,0 +1,54 @@
# 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 openstack.common import quota_set
from openstack import resource
class QuotaSet(quota_set.QuotaSet):
# We generally only want compute QS support max_microversion. Otherwise be
# explicit and list all the attributes
_max_microversion = '2.56'
#: Properties
#: The number of allowed server cores for each tenant.
cores = resource.Body('cores', type=int)
#: The number of allowed fixed IP addresses for each tenant. Must be
#: equal to or greater than the number of allowed servers.
fixed_ips = resource.Body('fixed_ips', type=int)
#: The number of allowed floating IP addresses for each tenant.
floating_ips = resource.Body('floating_ips', type=int)
#: The number of allowed bytes of content for each injected file.
injected_file_content_bytes = resource.Body(
'injected_file_content_bytes', type=int)
#: The number of allowed bytes for each injected file path.
injected_file_path_bytes = resource.Body(
'injected_file_path_bytes', type=int)
#: The number of allowed injected files for each tenant.
injected_files = resource.Body('injected_files', type=int)
#: The number of allowed servers for each tenant.
instances = resource.Body('instances', type=int)
#: The number of allowed key pairs for each user.
key_pairs = resource.Body('key_pairs', type=int)
#: The number of allowed metadata items for each server.
metadata_items = resource.Body('metadata_items', type=int)
#: The number of private networks that can be created per project.
networks = resource.Body('networks', type=int)
#: The amount of allowed server RAM, in MiB, for each tenant.
ram = resource.Body('ram', type=int)
#: The number of allowed rules for each security group.
security_group_rules = resource.Body('security_group_rules', type=int)
#: The number of allowed security groups for each tenant.
security_groups = resource.Body('security_groups', type=int)
#: The number of allowed server groups for each tenant.
server_groups = resource.Body('server_groups', type=int)
#: The number of allowed members for each server group.
server_group_members = resource.Body('server_group_members', type=int)

View File

@ -0,0 +1,48 @@
# 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 openstack.tests.functional import base
class TestQS(base.BaseFunctionalTest):
def test_qs(self):
sot = self.conn.compute.get_quota_set(
self.conn.current_project_id
)
self.assertIsNotNone(sot.key_pairs)
def test_qs_user(self):
sot = self.conn.compute.get_quota_set(
self.conn.current_project_id,
user_id=self.conn.session.auth.get_user_id(self.conn.compute)
)
self.assertIsNotNone(sot.key_pairs)
def test_update(self):
sot = self.conn.compute.get_quota_set(
self.conn.current_project_id
)
self.conn.compute.update_quota_set(
sot,
query={
'user_id': self.conn.session.auth.get_user_id(
self.conn.compute)
},
key_pairs=100
)
def test_revert(self):
self.conn.compute.revert_quota_set(
self.conn.current_project_id,
user_id=self.conn.session.auth.get_user_id(self.conn.compute)
)

View File

@ -21,12 +21,14 @@ from openstack.compute.v2 import hypervisor
from openstack.compute.v2 import image from openstack.compute.v2 import image
from openstack.compute.v2 import keypair from openstack.compute.v2 import keypair
from openstack.compute.v2 import limits from openstack.compute.v2 import limits
from openstack.compute.v2 import quota_set
from openstack.compute.v2 import server from openstack.compute.v2 import server
from openstack.compute.v2 import server_group from openstack.compute.v2 import server_group
from openstack.compute.v2 import server_interface from openstack.compute.v2 import server_interface
from openstack.compute.v2 import server_ip from openstack.compute.v2 import server_ip
from openstack.compute.v2 import server_remote_console from openstack.compute.v2 import server_remote_console
from openstack.compute.v2 import service from openstack.compute.v2 import service
from openstack import resource
from openstack.tests.unit import test_proxy_base from openstack.tests.unit import test_proxy_base
@ -1079,3 +1081,86 @@ class TestCompute(TestComputeProxy):
type='fake_type', type='fake_type',
protocol=None) protocol=None)
self.assertEqual(console_fake['url'], ret['url']) self.assertEqual(console_fake['url'], ret['url'])
class TestQuota(TestComputeProxy):
def test_get(self):
self._verify(
'openstack.resource.Resource.fetch',
self.proxy.get_quota_set,
method_args=['prj'],
expected_args=[self.proxy],
expected_kwargs={
'error_message': None,
'requires_id': False,
'usage': False,
},
method_result=quota_set.QuotaSet(),
expected_result=quota_set.QuotaSet()
)
def test_get_query(self):
self._verify(
'openstack.resource.Resource.fetch',
self.proxy.get_quota_set,
method_args=['prj'],
method_kwargs={
'usage': True,
'user_id': 'uid'
},
expected_args=[self.proxy],
expected_kwargs={
'error_message': None,
'requires_id': False,
'usage': True,
'user_id': 'uid'
}
)
def test_get_defaults(self):
self._verify(
'openstack.resource.Resource.fetch',
self.proxy.get_quota_set_defaults,
method_args=['prj'],
expected_args=[self.proxy],
expected_kwargs={
'error_message': None,
'requires_id': False,
'base_path': '/os-quota-sets/defaults'
}
)
def test_reset(self):
self._verify(
'openstack.resource.Resource.delete',
self.proxy.revert_quota_set,
method_args=['prj'],
method_kwargs={'user_id': 'uid'},
expected_args=[self.proxy],
expected_kwargs={
'user_id': 'uid'
}
)
@mock.patch('openstack.proxy.Proxy._get_resource', autospec=True)
def test_update(self, gr_mock):
gr_mock.return_value = resource.Resource()
gr_mock.commit = mock.Mock()
self._verify(
'openstack.resource.Resource.commit',
self.proxy.update_quota_set,
method_args=['qs'],
method_kwargs={
'query': {'user_id': 'uid'},
'a': 'b',
},
expected_args=[self.proxy],
expected_kwargs={
'user_id': 'uid'
}
)
gr_mock.assert_called_with(
self.proxy,
quota_set.QuotaSet,
'qs', a='b'
)

View File

@ -0,0 +1,4 @@
---
features:
- |
Add support for QuotaSet in the compute service.