Add commands for default type overrides
This patch adds command for set,get and delete default volume types for projects. This patch adds 3 commands : 1) Set Set a default volume type for a project cinder --os-volume-api-version 3.62 default-type-set <vol-type-id> <project-id> 2) Get Get the default volume type for a project cinder --os-volume-api-version 3.62 default-type-list --project-id <project-id> Get all default types cinder --os-volume-api-version 3.62 default-type-list 3) Unset Unset default volume type for a project cinder --os-volume-api-version 3.62 default-type-unset <project-id> Implements: Blueprint multiple-default-volume-types Change-Id: Id2fb00c218edbb98df3193577dba6a897c6e73f6
This commit is contained in:
parent
76f2b91d9a
commit
7ee7d376a1
@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
# key is a deprecated version and value is an alternative version.
|
# key is a deprecated version and value is an alternative version.
|
||||||
DEPRECATED_VERSIONS = {"2": "3"}
|
DEPRECATED_VERSIONS = {"2": "3"}
|
||||||
DEPRECATED_VERSION = "2.0"
|
DEPRECATED_VERSION = "2.0"
|
||||||
MAX_VERSION = "3.61"
|
MAX_VERSION = "3.62"
|
||||||
MIN_VERSION = "3.0"
|
MIN_VERSION = "3.0"
|
||||||
|
|
||||||
_SUBSTITUTIONS = {}
|
_SUBSTITUTIONS = {}
|
||||||
|
@ -331,6 +331,26 @@ class Manager(common_base.HookableMixin):
|
|||||||
else:
|
else:
|
||||||
return self.resource_class(self, body, loaded=True)
|
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)):
|
class ManagerWithFind(six.with_metaclass(abc.ABCMeta, Manager)):
|
||||||
"""
|
"""
|
||||||
|
@ -269,6 +269,12 @@ class SessionClient(adapter.LegacyJsonAdapter):
|
|||||||
def get_with_base_url(self, url, **kwargs):
|
def get_with_base_url(self, url, **kwargs):
|
||||||
return self._cs_request_base_url(url, 'GET', **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):
|
class HTTPClient(object):
|
||||||
|
|
||||||
|
@ -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):
|
class FakeClient(fakes.FakeClient, client.Client):
|
||||||
|
|
||||||
def __init__(self, api_version=None, *args, **kwargs):
|
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)})
|
{'transfer': _stub_transfer(transfer1, base_uri, tenant_id)})
|
||||||
|
|
||||||
def get_with_base_url(self, url, **kw):
|
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()
|
server_versions = _stub_server_versions()
|
||||||
return (200, {'versions': 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
|
# Services
|
||||||
#
|
#
|
||||||
|
46
cinderclient/tests/unit/v3/test_default_types.py
Normal file
46
cinderclient/tests/unit/v3/test_default_types.py
Normal file
@ -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')
|
@ -1611,3 +1611,33 @@ class ShellTest(utils.TestCase):
|
|||||||
def test_transfer_list_with_filters(self, command, expected):
|
def test_transfer_list_with_filters(self, command, expected):
|
||||||
self.run_command('--os-volume-api-version 3.52 %s' % command)
|
self.run_command('--os-volume-api-version 3.52 %s' % command)
|
||||||
self.assert_called('GET', expected)
|
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')
|
||||||
|
@ -21,6 +21,7 @@ from cinderclient.v3 import capabilities
|
|||||||
from cinderclient.v3 import cgsnapshots
|
from cinderclient.v3 import cgsnapshots
|
||||||
from cinderclient.v3 import clusters
|
from cinderclient.v3 import clusters
|
||||||
from cinderclient.v3 import consistencygroups
|
from cinderclient.v3 import consistencygroups
|
||||||
|
from cinderclient.v3 import default_types
|
||||||
from cinderclient.v3 import group_snapshots
|
from cinderclient.v3 import group_snapshots
|
||||||
from cinderclient.v3 import group_types
|
from cinderclient.v3 import group_types
|
||||||
from cinderclient.v3 import groups
|
from cinderclient.v3 import groups
|
||||||
@ -80,6 +81,7 @@ class Client(object):
|
|||||||
volume_type_access.VolumeTypeAccessManager(self)
|
volume_type_access.VolumeTypeAccessManager(self)
|
||||||
self.volume_encryption_types = \
|
self.volume_encryption_types = \
|
||||||
volume_encryption_types.VolumeEncryptionTypeManager(self)
|
volume_encryption_types.VolumeEncryptionTypeManager(self)
|
||||||
|
self.default_types = default_types.DefaultVolumeTypeManager(self)
|
||||||
self.qos_specs = qos_specs.QoSSpecsManager(self)
|
self.qos_specs = qos_specs.QoSSpecsManager(self)
|
||||||
self.quota_classes = quota_classes.QuotaClassSetManager(self)
|
self.quota_classes = quota_classes.QuotaClassSetManager(self)
|
||||||
self.quotas = quotas.QuotaSetManager(self)
|
self.quotas = quotas.QuotaSetManager(self)
|
||||||
|
65
cinderclient/v3/default_types.py
Normal file
65
cinderclient/v3/default_types.py
Normal file
@ -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)
|
@ -2598,3 +2598,54 @@ def do_transfer_list(cs, args):
|
|||||||
columns = ['ID', 'Volume ID', 'Name']
|
columns = ['ID', 'Volume ID', 'Name']
|
||||||
utils.print_list(transfers, columns)
|
utils.print_list(transfers, columns)
|
||||||
AppendFilters.filters = []
|
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))
|
||||||
|
@ -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.
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user