Merge "Add support for default volume types"

This commit is contained in:
Zuul 2024-12-18 12:48:29 +00:00 committed by Gerrit Code Review
commit 64138b59c9
6 changed files with 272 additions and 0 deletions

View File

@ -173,3 +173,11 @@ Helpers
.. autoclass:: openstack.block_storage.v3._proxy.Proxy
:noindex:
:members: wait_for_status, wait_for_delete
Default Volume Types
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.block_storage.v3._proxy.Proxy
:noindex:
:members: default_types, show_default_type, set_default_type,
unset_default_type

View File

@ -19,6 +19,7 @@ from openstack.block_storage.v3 import availability_zone
from openstack.block_storage.v3 import backup as _backup
from openstack.block_storage.v3 import block_storage_summary as _summary
from openstack.block_storage.v3 import capabilities as _capabilities
from openstack.block_storage.v3 import default_type as _default_type
from openstack.block_storage.v3 import extension as _extension
from openstack.block_storage.v3 import group as _group
from openstack.block_storage.v3 import group_snapshot as _group_snapshot
@ -535,6 +536,83 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
return self._update(_type.TypeEncryption, encryption, **attrs)
# ====== DEFAULT TYPES ======
def default_types(self):
"""Lists default types.
:returns: List of default types associated to projects.
"""
# This is required since previously default types did not accept
# URL with project ID
if not utils.supports_microversion(self, '3.67'):
raise exceptions.SDKException(
'List default types require at least microversion 3.67'
)
return self._list(_default_type.DefaultType)
def show_default_type(self, project):
"""Show default type for a project.
:param project: The value can be either the ID of a project or a
:class:`~openstack.identity.v3.project.Project` instance.
:returns: Default type associated to the project.
"""
# This is required since previously default types did not accept
# URL with project ID
if not utils.supports_microversion(self, '3.67'):
raise exceptions.SDKException(
'Show default type require at least microversion 3.67'
)
project_id = resource.Resource._get_id(project)
return self._get(_default_type.DefaultType, project_id)
def set_default_type(self, project, type):
"""Set default type for a project.
:param project: The value can be either the ID of a project or a
:class:`~openstack.identity.v3.project.Project` instance.
:param type: The value can be either the ID of a type or a
:class:`~openstack.block_storage.v3.type.Type` instance.
:returns: Dictionary of project ID and it's associated default type.
"""
# This is required since previously default types did not accept
# URL with project ID
if not utils.supports_microversion(self, '3.67'):
raise exceptions.SDKException(
'Set default type require at least microversion 3.67'
)
type_id = resource.Resource._get_id(type)
project_id = resource.Resource._get_id(project)
return self._create(
_default_type.DefaultType,
id=project_id,
volume_type_id=type_id,
)
def unset_default_type(self, project):
"""Unset default type for a project.
:param project: The value can be either the ID of a project or a
:class:`~openstack.identity.v3.project.Project` instance.
:returns: ``None``
"""
# This is required since previously default types did not accept
# URL with project ID
if not utils.supports_microversion(self, '3.67'):
raise exceptions.SDKException(
'Unset default type require at least microversion 3.67'
)
project_id = resource.Resource._get_id(project)
self._delete(_default_type.DefaultType, project_id)
# ====== VOLUMES ======
def get_volume(self, volume):
"""Get a single volume

View File

@ -0,0 +1,56 @@
# 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 import resource
class DefaultType(resource.Resource):
resource_key = "default_type"
resources_key = "default_types"
base_path = "/default-types"
# capabilities
allow_fetch = True
allow_create = True
allow_delete = True
allow_list = True
# Create and update use the same PUT API
create_requires_id = True
create_method = 'PUT'
_max_microversion = "3.67"
# Properties
#: The UUID of the project.
project_id = resource.Body("project_id")
#: The UUID for an existing volume type.
volume_type_id = resource.Body("volume_type_id")
def _prepare_request_body(
self,
patch,
prepend_key,
*,
resource_request_key=None,
):
body = self._body.dirty
# Set operation expects volume_type instead of
# volume_type_id
if body.get('volume_type_id'):
body['volume_type'] = body.pop('volume_type_id')
# When setting a default type, we want the ID to be
# appended in URL but not in the request body
if body.get('id'):
body.pop('id')
body = {self.resource_key: body}
return body

View File

@ -0,0 +1,66 @@
# 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.block_storage.v3 import default_type as _default_type
from openstack.tests.functional.block_storage.v3 import base
class TestDefaultType(base.BaseBlockStorageTest):
def setUp(self):
super().setUp()
if not self._op_name:
self.skip("Operator cloud must be set for this test")
self._set_operator_cloud(block_storage_api_version='3.67')
self.PROJECT_ID = self.create_temporary_project().id
def test_default_type(self):
# Create a volume type
type_name = self.getUniqueString()
volume_type_id = self.operator_cloud.block_storage.create_type(
name=type_name,
).id
# Set default type for a project
default_type = self.conn.block_storage.set_default_type(
self.PROJECT_ID,
volume_type_id,
)
self.assertIsInstance(default_type, _default_type.DefaultType)
# Show default type for a project
default_type = self.conn.block_storage.show_default_type(
self.PROJECT_ID
)
self.assertIsInstance(default_type, _default_type.DefaultType)
self.assertEqual(volume_type_id, default_type.volume_type_id)
# List all default types
default_types = self.conn.block_storage.default_types()
for default_type in default_types:
self.assertIsInstance(default_type, _default_type.DefaultType)
# There could be existing default types set in the environment
# Just verify that the default type we have set is correct
if self.PROJECT_ID == default_type.project_id:
self.assertEqual(volume_type_id, default_type.volume_type_id)
# Unset default type for a project
default_type = self.conn.block_storage.unset_default_type(
self.PROJECT_ID
)
self.assertIsNone(default_type)
# Delete the volume type
vol_type = self.operator_cloud.block_storage.delete_type(
volume_type_id,
ignore_missing=False,
)
self.assertIsNone(vol_type)

View File

@ -0,0 +1,55 @@
# 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 unittest import mock
from keystoneauth1 import adapter
from openstack.block_storage.v3 import default_type
from openstack.tests.unit import base
PROJECT_ID = 'd5e678b5-f88b-411c-876b-f6ec2ba999bf'
VOLUME_TYPE_ID = 'adef1cf8-736e-4b62-a2db-f8b6b6c1d953'
DEFAULT_TYPE = {
'project_id': PROJECT_ID,
'volume_type_id': VOLUME_TYPE_ID,
}
class TestDefaultType(base.TestCase):
def setUp(self):
super().setUp()
self.resp = mock.Mock()
self.resp.body = None
self.resp.status_code = 200
self.resp.json = mock.Mock(return_value=self.resp.body)
self.sess = mock.Mock(spec=adapter.Adapter)
self.sess.default_microversion = '3.67'
self.sess.post = mock.Mock(return_value=self.resp)
self.sess._get_connection = mock.Mock(return_value=self.cloud)
def test_basic(self):
sot = default_type.DefaultType(**DEFAULT_TYPE)
self.assertEqual("default_type", sot.resource_key)
self.assertEqual("default_types", sot.resources_key)
self.assertEqual("/default-types", sot.base_path)
self.assertTrue(sot.allow_create)
self.assertTrue(sot.allow_fetch)
self.assertTrue(sot.allow_delete)
self.assertTrue(sot.allow_list)
def test_create(self):
sot = default_type.DefaultType(**DEFAULT_TYPE)
self.assertEqual(DEFAULT_TYPE["project_id"], sot.project_id)
self.assertEqual(DEFAULT_TYPE["volume_type_id"], sot.volume_type_id)

View File

@ -0,0 +1,9 @@
---
features:
- |
Added support for the following operations:
* Set default volume type
* Get default volume type
* List default volume type
* Unset default volume type