Add support for default volume types
This patch adds support for default volume type operations: 1. Set 2. Unset 3. List 4. Get Change-Id: Iac22d3c989b2b19fe4f167011aec1304becc4f34
This commit is contained in:
@@ -173,3 +173,11 @@ Helpers
|
|||||||
.. autoclass:: openstack.block_storage.v3._proxy.Proxy
|
.. autoclass:: openstack.block_storage.v3._proxy.Proxy
|
||||||
:noindex:
|
:noindex:
|
||||||
:members: wait_for_status, wait_for_delete
|
: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
|
||||||
|
@@ -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 backup as _backup
|
||||||
from openstack.block_storage.v3 import block_storage_summary as _summary
|
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 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 extension as _extension
|
||||||
from openstack.block_storage.v3 import group as _group
|
from openstack.block_storage.v3 import group as _group
|
||||||
from openstack.block_storage.v3 import group_snapshot as _group_snapshot
|
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)
|
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 ======
|
# ====== VOLUMES ======
|
||||||
def get_volume(self, volume):
|
def get_volume(self, volume):
|
||||||
"""Get a single volume
|
"""Get a single volume
|
||||||
|
56
openstack/block_storage/v3/default_type.py
Normal file
56
openstack/block_storage/v3/default_type.py
Normal 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
|
@@ -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)
|
55
openstack/tests/unit/block_storage/v3/test_default_type.py
Normal file
55
openstack/tests/unit/block_storage/v3/test_default_type.py
Normal 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)
|
@@ -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
|
Reference in New Issue
Block a user