summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2020-09-16 15:16:48 +0000
committerGerrit Code Review <review@openstack.org>2020-09-16 15:16:48 +0000
commit9bd87c5ce9abde7134ee607c38184cdf9690cab1 (patch)
treefbfb78fcab05600cc0f06f079486a332704d43d9
parent7397f709579427a96919cf5036dcc821941a6f20 (diff)
parent7ee7d376a19cebbf7d8bc6d273f7e7daba552526 (diff)
downloadpython-cinderclient-9bd87c5ce9abde7134ee607c38184cdf9690cab1.tar.gz
Merge "Add commands for default type overrides"
-rw-r--r--cinderclient/api_versions.py2
-rw-r--r--cinderclient/base.py20
-rw-r--r--cinderclient/client.py6
-rw-r--r--cinderclient/tests/unit/v2/fakes.py50
-rw-r--r--cinderclient/tests/unit/v3/test_default_types.py46
-rw-r--r--cinderclient/tests/unit/v3/test_shell.py30
-rw-r--r--cinderclient/v3/client.py2
-rw-r--r--cinderclient/v3/default_types.py65
-rw-r--r--cinderclient/v3/shell.py51
-rw-r--r--releasenotes/notes/project-default-types-727156d1db10a24d.yaml6
10 files changed, 277 insertions, 1 deletions
diff --git a/cinderclient/api_versions.py b/cinderclient/api_versions.py
index dbd9d1e..ff4cc93 100644
--- a/cinderclient/api_versions.py
+++ b/cinderclient/api_versions.py
@@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__)
# key is a deprecated version and value is an alternative version.
DEPRECATED_VERSIONS = {"2": "3"}
DEPRECATED_VERSION = "2.0"
-MAX_VERSION = "3.61"
+MAX_VERSION = "3.62"
MIN_VERSION = "3.0"
_SUBSTITUTIONS = {}
diff --git a/cinderclient/base.py b/cinderclient/base.py
index a317ad4..40ce381 100644
--- a/cinderclient/base.py
+++ b/cinderclient/base.py
@@ -331,6 +331,26 @@ class Manager(common_base.HookableMixin):
else:
return self.resource_class(self, body, loaded=True)
+ def _get_all_with_base_url(self, url, response_key=None):
+ resp, body = self.api.client.get_with_base_url(url)
+ if response_key:
+ if isinstance(body[response_key], list):
+ return [self.resource_class(self, res, loaded=True)
+ for res in body[response_key] if res]
+ return self.resource_class(self, body[response_key],
+ loaded=True)
+ return self.resource_class(self, body, loaded=True)
+
+ def _create_update_with_base_url(self, url, body, response_key=None):
+ resp, body = self.api.client.create_update_with_base_url(
+ url, body=body)
+ if response_key:
+ return self.resource_class(self, body[response_key], loaded=True)
+ return self.resource_class(self, body, loaded=True)
+
+ def _delete_with_base_url(self, url, response_key=None):
+ self.api.client.delete_with_base_url(url)
+
class ManagerWithFind(six.with_metaclass(abc.ABCMeta, Manager)):
"""
diff --git a/cinderclient/client.py b/cinderclient/client.py
index 63573a5..ffc491f 100644
--- a/cinderclient/client.py
+++ b/cinderclient/client.py
@@ -269,6 +269,12 @@ class SessionClient(adapter.LegacyJsonAdapter):
def get_with_base_url(self, url, **kwargs):
return self._cs_request_base_url(url, 'GET', **kwargs)
+ def create_update_with_base_url(self, url, **kwargs):
+ return self._cs_request_base_url(url, 'PUT', **kwargs)
+
+ def delete_with_base_url(self, url, **kwargs):
+ return self._cs_request_base_url(url, 'DELETE', **kwargs)
+
class HTTPClient(object):
diff --git a/cinderclient/tests/unit/v2/fakes.py b/cinderclient/tests/unit/v2/fakes.py
index 0cf1faa..0dd269e 100644
--- a/cinderclient/tests/unit/v2/fakes.py
+++ b/cinderclient/tests/unit/v2/fakes.py
@@ -309,6 +309,30 @@ def _stub_server_versions():
]
+def stub_default_type():
+ return {
+ 'default_type': {
+ 'project_id': '629632e7-99d2-4c40-9ae3-106fa3b1c9b7',
+ 'volume_type_id': '4c298f16-e339-4c80-b934-6cbfcb7525a0'
+ }
+ }
+
+
+def stub_default_types():
+ return {
+ 'default_types': [
+ {
+ 'project_id': '629632e7-99d2-4c40-9ae3-106fa3b1c9b7',
+ 'volume_type_id': '4c298f16-e339-4c80-b934-6cbfcb7525a0'
+ },
+ {
+ 'project_id': 'a0c01994-1245-416e-8fc9-1aca86329bfd',
+ 'volume_type_id': 'ff094b46-f82a-4a74-9d9e-d3d08116ad93'
+ }
+ ]
+ }
+
+
class FakeClient(fakes.FakeClient, client.Client):
def __init__(self, api_version=None, *args, **kwargs):
@@ -1055,9 +1079,35 @@ class FakeHTTPClient(base_client.HTTPClient):
{'transfer': _stub_transfer(transfer1, base_uri, tenant_id)})
def get_with_base_url(self, url, **kw):
+ if 'default-types' in url:
+ return self._cs_request(url, 'GET', **kw)
server_versions = _stub_server_versions()
return (200, {'versions': server_versions})
+ def create_update_with_base_url(self, url, **kwargs):
+ return self._cs_request(url, 'PUT', **kwargs)
+
+ def put_v3_default_types_629632e7_99d2_4c40_9ae3_106fa3b1c9b7(
+ self, **kwargs):
+ default_type = stub_default_type()
+ return (200, {}, default_type)
+
+ def get_v3_default_types_629632e7_99d2_4c40_9ae3_106fa3b1c9b7(
+ self, **kw):
+ default_types = stub_default_type()
+ return (200, {}, default_types)
+
+ def get_v3_default_types(self, **kw):
+ default_types = stub_default_types()
+ return (200, {}, default_types)
+
+ def delete_with_base_url(self, url, **kwargs):
+ return self._cs_request(url, 'DELETE', **kwargs)
+
+ def delete_v3_default_types_629632e7_99d2_4c40_9ae3_106fa3b1c9b7(
+ self, **kwargs):
+ return (204, {}, {})
+
#
# Services
#
diff --git a/cinderclient/tests/unit/v3/test_default_types.py b/cinderclient/tests/unit/v3/test_default_types.py
new file mode 100644
index 0000000..621aeb8
--- /dev/null
+++ b/cinderclient/tests/unit/v3/test_default_types.py
@@ -0,0 +1,46 @@
+# All Rights Reserved.
+#
+# 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 cinderclient import api_versions
+from cinderclient.tests.unit import utils
+from cinderclient.tests.unit.v3 import fakes
+
+defaults = fakes.FakeClient(api_versions.APIVersion('3.62'))
+
+
+class VolumeTypeDefaultTest(utils.TestCase):
+
+ def test_set(self):
+ defaults.default_types.create('4c298f16-e339-4c80-b934-6cbfcb7525a0',
+ '629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+ defaults.assert_called(
+ 'PUT', 'v3/default-types/629632e7-99d2-4c40-9ae3-106fa3b1c9b7',
+ body={'default_type':
+ {'volume_type': '4c298f16-e339-4c80-b934-6cbfcb7525a0'}}
+ )
+
+ def test_get(self):
+ defaults.default_types.list('629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+ defaults.assert_called(
+ 'GET', 'v3/default-types/629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+
+ def test_get_all(self):
+ defaults.default_types.list()
+ defaults.assert_called(
+ 'GET', 'v3/default-types')
+
+ def test_unset(self):
+ defaults.default_types.delete('629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+ defaults.assert_called(
+ 'DELETE', 'v3/default-types/629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py
index 8338a34..0332ae3 100644
--- a/cinderclient/tests/unit/v3/test_shell.py
+++ b/cinderclient/tests/unit/v3/test_shell.py
@@ -1611,3 +1611,33 @@ class ShellTest(utils.TestCase):
def test_transfer_list_with_filters(self, command, expected):
self.run_command('--os-volume-api-version 3.52 %s' % command)
self.assert_called('GET', expected)
+
+ def test_default_type_set(self):
+ self.run_command('--os-volume-api-version 3.62 default-type-set '
+ '4c298f16-e339-4c80-b934-6cbfcb7525a0 '
+ '629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+ body = {
+ 'default_type':
+ {
+ 'volume_type': '4c298f16-e339-4c80-b934-6cbfcb7525a0'
+ }
+ }
+ self.assert_called(
+ 'PUT', 'v3/default-types/629632e7-99d2-4c40-9ae3-106fa3b1c9b7',
+ body=body)
+
+ def test_default_type_list_project(self):
+ self.run_command('--os-volume-api-version 3.62 default-type-list '
+ '--project-id 629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+ self.assert_called(
+ 'GET', 'v3/default-types/629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+
+ def test_default_type_list(self):
+ self.run_command('--os-volume-api-version 3.62 default-type-list')
+ self.assert_called('GET', 'v3/default-types')
+
+ def test_default_type_delete(self):
+ self.run_command('--os-volume-api-version 3.62 default-type-unset '
+ '629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
+ self.assert_called(
+ 'DELETE', 'v3/default-types/629632e7-99d2-4c40-9ae3-106fa3b1c9b7')
diff --git a/cinderclient/v3/client.py b/cinderclient/v3/client.py
index 5703826..770d9d6 100644
--- a/cinderclient/v3/client.py
+++ b/cinderclient/v3/client.py
@@ -21,6 +21,7 @@ from cinderclient.v3 import capabilities
from cinderclient.v3 import cgsnapshots
from cinderclient.v3 import clusters
from cinderclient.v3 import consistencygroups
+from cinderclient.v3 import default_types
from cinderclient.v3 import group_snapshots
from cinderclient.v3 import group_types
from cinderclient.v3 import groups
@@ -80,6 +81,7 @@ class Client(object):
volume_type_access.VolumeTypeAccessManager(self)
self.volume_encryption_types = \
volume_encryption_types.VolumeEncryptionTypeManager(self)
+ self.default_types = default_types.DefaultVolumeTypeManager(self)
self.qos_specs = qos_specs.QoSSpecsManager(self)
self.quota_classes = quota_classes.QuotaClassSetManager(self)
self.quotas = quotas.QuotaSetManager(self)
diff --git a/cinderclient/v3/default_types.py b/cinderclient/v3/default_types.py
new file mode 100644
index 0000000..58e04cc
--- /dev/null
+++ b/cinderclient/v3/default_types.py
@@ -0,0 +1,65 @@
+# 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.
+
+
+"""Default Volume Type interface."""
+
+from cinderclient import base
+
+
+class DefaultVolumeType(base.Resource):
+ """Default volume types for projects."""
+ def __repr__(self):
+ return "<DefaultVolumeType: %s>" % self.project_id
+
+
+class DefaultVolumeTypeManager(base.ManagerWithFind):
+ """Manage :class:`DefaultVolumeType` resources."""
+ resource_class = DefaultVolumeType
+
+ def create(self, volume_type, project_id):
+ """Creates a default volume type for a project
+
+ :param volume_type: Name or ID of the volume type
+ :param project_id: Project to set default type for
+ """
+
+ body = {
+ "default_type": {
+ "volume_type": volume_type
+ }
+ }
+
+ return self._create_update_with_base_url(
+ 'v3/default-types/%s' % project_id, body,
+ response_key='default_type')
+
+ def list(self, project_id=None):
+ """List the default types."""
+
+ url = 'v3/default-types'
+ response_key = "default_types"
+
+ if project_id:
+ url += '/' + project_id
+ response_key = "default_type"
+
+ return self._get_all_with_base_url(url, response_key)
+
+ def delete(self, project_id):
+ """Removes the default volume type for a project
+
+ :param project_id: The ID of the project to unset default for.
+ """
+
+ return self._delete_with_base_url('v3/default-types/%s' % project_id)
diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py
index 1ccf02e..eaded7e 100644
--- a/cinderclient/v3/shell.py
+++ b/cinderclient/v3/shell.py
@@ -2598,3 +2598,54 @@ def do_transfer_list(cs, args):
columns = ['ID', 'Volume ID', 'Name']
utils.print_list(transfers, columns)
AppendFilters.filters = []
+
+
+@api_versions.wraps('3.62')
+@utils.arg('volume_type',
+ metavar='<volume_type>',
+ help='Name or ID of the volume type.')
+@utils.arg('project',
+ metavar='<project_id>',
+ help='ID of project for which to set default type.')
+def do_default_type_set(cs, args):
+ """Sets a default volume type for a project."""
+ volume_type = args.volume_type
+ project = args.project
+
+ default_type = cs.default_types.create(volume_type, project)
+ utils.print_dict(default_type._info)
+
+
+@api_versions.wraps('3.62')
+@utils.arg('--project-id',
+ metavar='<project_id>',
+ default=None,
+ help='ID of project for which to show the default type.')
+def do_default_type_list(cs, args):
+ """Lists all default volume types."""
+
+ project_id = args.project_id
+ default_types = cs.default_types.list(project_id)
+ columns = ['Volume Type ID', 'Project ID']
+ if project_id:
+ utils.print_dict(default_types._info)
+ else:
+ utils.print_list(default_types, columns)
+
+
+@api_versions.wraps('3.62')
+@utils.arg('project_id',
+ metavar='<project_id>',
+ nargs='+',
+ help='ID of project for which to unset default type.')
+def do_default_type_unset(cs, args):
+ """Unset default volume types."""
+
+ for project_id in args.project_id:
+ try:
+ cs.default_types.delete(project_id)
+ print("Default volume type for project %s has been unset "
+ "successfully." % (project_id))
+ except Exception as e:
+ print("Unset for default volume type for project %s failed: %s"
+ % (project_id, e))
diff --git a/releasenotes/notes/project-default-types-727156d1db10a24d.yaml b/releasenotes/notes/project-default-types-727156d1db10a24d.yaml
new file mode 100644
index 0000000..c4385a5
--- /dev/null
+++ b/releasenotes/notes/project-default-types-727156d1db10a24d.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Added support to set, get, and unset the default volume type for
+ projects with Block Storage API version 3.62 and higher.
+