diff options
Diffstat (limited to 'openstackclient')
30 files changed, 330 insertions, 163 deletions
diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py index c77a7848..742509e4 100644 --- a/openstackclient/common/clientmanager.py +++ b/openstackclient/common/clientmanager.py @@ -86,7 +86,7 @@ class ClientManager(object): self._pw_callback = pw_func self._url = self._cli_options.auth.get('url', None) self._region_name = self._cli_options.region_name - self._endpoint_type = self._cli_options.endpoint_type + self._interface = self._cli_options.interface self.timing = self._cli_options.timing @@ -185,22 +185,22 @@ class ClientManager(object): return self._auth_ref def get_endpoint_for_service_type(self, service_type, region_name=None, - endpoint_type='public'): + interface='public'): """Return the endpoint URL for the service type.""" - if not endpoint_type: - endpoint_type = 'public' + if not interface: + interface = 'public' # See if we are using password flow auth, i.e. we have a # service catalog to select endpoints from if self.auth_ref: endpoint = self.auth_ref.service_catalog.url_for( service_type=service_type, region_name=region_name, - endpoint_type=endpoint_type, + endpoint_type=interface, ) else: # Get the passed endpoint directly from the auth plugin endpoint = self.auth.get_endpoint(self.session, - interface=endpoint_type) + interface=interface) return endpoint diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py index 6cd35c05..2f8419f4 100644 --- a/openstackclient/common/utils.py +++ b/openstackclient/common/utils.py @@ -186,9 +186,9 @@ def sort_items(items, sort_str): :param items: a list or generator object of items :param sort_str: a string defining the sort rules, the format is - '<key1>:[direction1],<key2>:[direction2]...', direction can be 'asc' - for ascending or 'desc' for descending, if direction is not given, - it's ascending by default + '<key1>:[direction1],<key2>:[direction2]...', direction can be 'asc' + for ascending or 'desc' for descending, if direction is not given, + it's ascending by default :return: sorted items """ if not sort_str: diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py index 27d63a95..6ae87b79 100644 --- a/openstackclient/compute/client.py +++ b/openstackclient/compute/client.py @@ -48,9 +48,8 @@ def make_client(instance): extensions = [extension.Extension('list_extensions', list_extensions)] - # Remember endpoint_type only if it is set - kwargs = utils.build_kwargs_dict('endpoint_type', - instance._endpoint_type) + # Remember interface only if it is set + kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface) client = compute_client( session=instance.session, diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py index eb18a433..3458cf79 100644 --- a/openstackclient/compute/v2/flavor.py +++ b/openstackclient/compute/v2/flavor.py @@ -295,6 +295,7 @@ class UnsetFlavor(show.ShowOne): action='append', help='Property to remove from flavor ' '(repeat option to unset multiple properties)', + required=True, ) parser.add_argument( "flavor", diff --git a/openstackclient/identity/client.py b/openstackclient/identity/client.py index cc803511..d7b663dd 100644 --- a/openstackclient/identity/client.py +++ b/openstackclient/identity/client.py @@ -46,9 +46,8 @@ def make_client(instance): API_VERSIONS) LOG.debug('Instantiating identity client: %s', identity_client) - # Remember interface only if endpoint_type is set - kwargs = utils.build_kwargs_dict('interface', - instance._endpoint_type) + # Remember interface only if interface is set + kwargs = utils.build_kwargs_dict('interface', instance._interface) client = identity_client( session=instance.session, diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py index 2638b797..d0edb0bd 100644 --- a/openstackclient/identity/common.py +++ b/openstackclient/identity/common.py @@ -57,20 +57,32 @@ def find_domain(identity_client, name_or_id): def find_group(identity_client, name_or_id, domain_name_or_id=None): domain_id = _get_domain_id_if_requested(identity_client, domain_name_or_id) - return _find_identity_resource(identity_client.groups, name_or_id, - groups.Group, domain_id=domain_id) + if not domain_id: + return _find_identity_resource(identity_client.groups, name_or_id, + groups.Group) + else: + return _find_identity_resource(identity_client.groups, name_or_id, + groups.Group, domain_id=domain_id) def find_project(identity_client, name_or_id, domain_name_or_id=None): domain_id = _get_domain_id_if_requested(identity_client, domain_name_or_id) - return _find_identity_resource(identity_client.projects, name_or_id, - projects.Project, domain_id=domain_id) + if not domain_id: + return _find_identity_resource(identity_client.projects, name_or_id, + projects.Project) + else: + return _find_identity_resource(identity_client.projects, name_or_id, + projects.Project, domain_id=domain_id) def find_user(identity_client, name_or_id, domain_name_or_id=None): domain_id = _get_domain_id_if_requested(identity_client, domain_name_or_id) - return _find_identity_resource(identity_client.users, name_or_id, - users.User, domain_id=domain_id) + if not domain_id: + return _find_identity_resource(identity_client.users, name_or_id, + users.User) + else: + return _find_identity_resource(identity_client.users, name_or_id, + users.User, domain_id=domain_id) def _find_identity_resource(identity_client_manager, name_or_id, diff --git a/openstackclient/identity/v2_0/catalog.py b/openstackclient/identity/v2_0/catalog.py index c10001d0..e166c855 100644 --- a/openstackclient/identity/v2_0/catalog.py +++ b/openstackclient/identity/v2_0/catalog.py @@ -30,8 +30,10 @@ def _format_endpoints(eps=None): for index, ep in enumerate(eps): region = eps[index].get('region', '<none>') ret += region + '\n' - for url in ['publicURL', 'internalURL', 'adminURL']: - ret += " %s: %s\n" % (url, eps[index][url]) + for endpoint_type in ['publicURL', 'internalURL', 'adminURL']: + url = eps[index].get(endpoint_type) + if url: + ret += " %s: %s\n" % (endpoint_type, url) return ret diff --git a/openstackclient/identity/v3/trust.py b/openstackclient/identity/v3/trust.py index c8e5c4c7..5104864c 100644 --- a/openstackclient/identity/v3/trust.py +++ b/openstackclient/identity/v3/trust.py @@ -144,7 +144,7 @@ class CreateTrust(show.ShowOne): # Format roles into something sensible roles = trust._info.pop('roles') - msg = ''.join([r['name'] + ' ' for r in roles]) + msg = ' '.join(r['name'] for r in roles) trust._info['roles'] = msg return zip(*sorted(six.iteritems(trust._info))) @@ -215,7 +215,7 @@ class ShowTrust(show.ShowOne): # Format roles into something sensible roles = trust._info.pop('roles') - msg = ''.join([r['name'] + ' ' for r in roles]) + msg = ' '.join(r['name'] for r in roles) trust._info['roles'] = msg return zip(*sorted(six.iteritems(trust._info))) diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py index b72e0d15..459707d2 100644 --- a/openstackclient/identity/v3/user.py +++ b/openstackclient/identity/v3/user.py @@ -51,6 +51,7 @@ class CreateUser(show.ShowOne): metavar='<project>', help='Default project (name or ID)', ) + common.add_project_domain_option_to_parser(parser) parser.add_argument( '--password', metavar='<password>', @@ -96,10 +97,9 @@ class CreateUser(show.ShowOne): project_id = None if parsed_args.project: - project_id = utils.find_resource( - identity_client.projects, - parsed_args.project, - ).id + project_id = common.find_project(identity_client, + parsed_args.project, + parsed_args.project_domain).id domain_id = None if parsed_args.domain: @@ -301,6 +301,7 @@ class SetUser(command.Command): metavar='<project>', help='Set default project (name or ID)', ) + common.add_project_domain_option_to_parser(parser) parser.add_argument( '--password', metavar='<password>', @@ -367,8 +368,9 @@ class SetUser(command.Command): if parsed_args.description: kwargs['description'] = parsed_args.description if parsed_args.project: - project_id = utils.find_resource( - identity_client.projects, parsed_args.project).id + project_id = common.find_project(identity_client, + parsed_args.project, + parsed_args.project_domain).id kwargs['default_project'] = project_id kwargs['enabled'] = user.enabled if parsed_args.enable: diff --git a/openstackclient/image/client.py b/openstackclient/image/client.py index 8e2d6cd9..8fbf8c0f 100644 --- a/openstackclient/image/client.py +++ b/openstackclient/image/client.py @@ -46,7 +46,7 @@ def make_client(instance): endpoint = instance.get_endpoint_for_service_type( API_NAME, region_name=instance._region_name, - endpoint_type=instance._endpoint_type, + interface=instance._interface, ) client = image_client( @@ -69,7 +69,7 @@ def make_client(instance): endpoint=instance.get_endpoint_for_service_type( IMAGE_API_TYPE, region_name=instance._region_name, - endpoint_type=instance._endpoint_type, + interface=instance._interface, ) ) diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 30485202..4c019db6 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -299,7 +299,7 @@ class SaveImage(command.Command): image_client.images, parsed_args.image, ) - data = image_client.images.data(image) + data = image_client.images.data(image.id) gc_utils.save_image(data, parsed_args.file) diff --git a/openstackclient/network/client.py b/openstackclient/network/client.py index de08e5e2..0ef68852 100644 --- a/openstackclient/network/client.py +++ b/openstackclient/network/client.py @@ -47,12 +47,11 @@ def make_client(instance): endpoint = instance.get_endpoint_for_service_type( API_NAME, region_name=instance._region_name, - endpoint_type=instance._endpoint_type, + interface=instance._interface, ) # Remember endpoint_type only if it is set - kwargs = utils.build_kwargs_dict('endpoint_type', - instance._endpoint_type) + kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface) client = network_client( session=instance.session, diff --git a/openstackclient/object/client.py b/openstackclient/object/client.py index 676f6642..0359940d 100644 --- a/openstackclient/object/client.py +++ b/openstackclient/object/client.py @@ -36,7 +36,7 @@ def make_client(instance): endpoint = instance.get_endpoint_for_service_type( 'object-store', region_name=instance._region_name, - endpoint_type=instance._endpoint_type, + interface=instance._interface, ) client = object_store_v1.APIv1( diff --git a/openstackclient/object/v1/lib/__init__.py b/openstackclient/object/v1/lib/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/openstackclient/object/v1/lib/__init__.py +++ /dev/null diff --git a/openstackclient/shell.py b/openstackclient/shell.py index b4e5904c..319f10de 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -209,14 +209,14 @@ class OpenStackShell(app.App): DEFAULT_DOMAIN + ' (Env: OS_DEFAULT_DOMAIN)') parser.add_argument( - '--os-endpoint-type', - metavar='<endpoint-type>', - dest='endpoint_type', + '--os-interface', + metavar='<interface>', + dest='interface', choices=['admin', 'public', 'internal'], - default=utils.env('OS_ENDPOINT_TYPE'), - help='Select an endpoint type.' - ' Valid endpoint types: [admin, public, internal].' - ' (Env: OS_ENDPOINT_TYPE)') + default=utils.env('OS_INTERFACE'), + help='Select an interface type.' + ' Valid interface types: [admin, public, internal].' + ' (Env: OS_INTERFACE)') parser.add_argument( '--timing', default=False, @@ -240,9 +240,9 @@ class OpenStackShell(app.App): # Set the default plugin to token_endpoint if url and token are given if (self.options.url and self.options.token): # Use service token authentication - cloud_config.set_default('auth_type', 'token_endpoint') + auth_type = 'token_endpoint' else: - cloud_config.set_default('auth_type', 'osc_password') + auth_type = 'osc_password' self.log.debug("options: %s", self.options) project_id = getattr(self.options, 'project_id', None) @@ -263,10 +263,11 @@ class OpenStackShell(app.App): self.options.project_name = tenant_name # Do configuration file handling - # Ignore the default value of endpoint_type. Only if it is set later + # Ignore the default value of interface. Only if it is set later # will it be used. cc = cloud_config.OpenStackConfig( - override_defaults={'endpoint_type': None, }) + override_defaults={'interface': None, + 'auth_type': auth_type, }) self.log.debug("defaults: %s", cc.defaults) self.cloud = cc.get_one_cloud( diff --git a/openstackclient/tests/common/test_clientmanager.py b/openstackclient/tests/common/test_clientmanager.py index e86ef509..29cc59ed 100644 --- a/openstackclient/tests/common/test_clientmanager.py +++ b/openstackclient/tests/common/test_clientmanager.py @@ -54,7 +54,7 @@ class FakeOptions(object): self.identity_api_version = '2.0' self.timing = None self.region_name = None - self.endpoint_type = None + self.interface = None self.url = None self.auth = {} self.default_domain = 'default' @@ -124,7 +124,7 @@ class TestClientManager(utils.TestCase): auth_url=fakes.AUTH_URL, ), auth_type='v2token', - endpoint_type=fakes.ENDPOINT_TYPE, + interface=fakes.INTERFACE, region_name=fakes.REGION_NAME, ), api_version=API_VERSION, @@ -141,8 +141,8 @@ class TestClientManager(utils.TestCase): auth_v2.Token, ) self.assertEqual( - fakes.ENDPOINT_TYPE, - client_manager._endpoint_type, + fakes.INTERFACE, + client_manager._interface, ) self.assertEqual( fakes.REGION_NAME, diff --git a/openstackclient/tests/common/test_extension.py b/openstackclient/tests/common/test_extension.py index 8327a414..6d34bdd8 100644 --- a/openstackclient/tests/common/test_extension.py +++ b/openstackclient/tests/common/test_extension.py @@ -52,13 +52,6 @@ class TestExtensionList(TestExtension): loaded=True, ), ] - self.network_extensions_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.EXTENSION), - loaded=True, - ), - ] # Get the command object to test self.cmd = extension.ListExtension(self.app, None) diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index a9322ec3..ff69c190 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -27,7 +27,7 @@ USERNAME = "itchy" PASSWORD = "scratchy" PROJECT_NAME = "poochie" REGION_NAME = "richie" -ENDPOINT_TYPE = "catchy" +INTERFACE = "catchy" TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, user_name=USERNAME) diff --git a/openstackclient/tests/identity/v2_0/test_catalog.py b/openstackclient/tests/identity/v2_0/test_catalog.py index fe13d78d..7f1835d6 100644 --- a/openstackclient/tests/identity/v2_0/test_catalog.py +++ b/openstackclient/tests/identity/v2_0/test_catalog.py @@ -84,6 +84,46 @@ class TestCatalogList(TestCatalog): ), ) self.assertEqual(datalist, tuple(data)) + def test_catalog_list_with_endpoint_url(self): + fake_service = { + 'id': 'qwertyuiop', + 'type': 'compute', + 'name': 'supernova', + 'endpoints': [ + { + 'region': 'one', + 'publicURL': 'https://public.one.example.com', + }, + { + 'region': 'two', + 'publicURL': 'https://public.two.example.com', + 'internalURL': 'https://internal.two.example.com', + }, + ], + } + self.sc_mock.service_catalog.get_data.return_value = [ + fake_service, + ] + + arglist = [] + verifylist = [] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + self.sc_mock.service_catalog.get_data.assert_called_with() + + collist = ('Name', 'Type', 'Endpoints') + self.assertEqual(collist, columns) + datalist = (( + 'supernova', + 'compute', + 'one\n publicURL: https://public.one.example.com\n' + 'two\n publicURL: https://public.two.example.com\n ' + 'internalURL: https://internal.two.example.com\n' + ), ) + self.assertEqual(datalist, tuple(data)) + class TestCatalogShow(TestCatalog): diff --git a/openstackclient/tests/identity/v3/test_trust.py b/openstackclient/tests/identity/v3/test_trust.py index b3fbe7f0..b90e7815 100644 --- a/openstackclient/tests/identity/v3/test_trust.py +++ b/openstackclient/tests/identity/v3/test_trust.py @@ -107,7 +107,7 @@ class TestTrustCreate(TestTrust): identity_fakes.trust_id, identity_fakes.trust_impersonation, identity_fakes.project_id, - identity_fakes.role_name + ' ', + identity_fakes.role_name, identity_fakes.user_id, identity_fakes.user_id ) @@ -222,7 +222,7 @@ class TestTrustShow(TestTrust): identity_fakes.trust_id, identity_fakes.trust_impersonation, identity_fakes.project_id, - identity_fakes.role_name + ' ', + identity_fakes.role_name, identity_fakes.user_id, identity_fakes.user_id ) diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py index 18fe9016..76d5f834 100644 --- a/openstackclient/tests/identity/v3/test_user.py +++ b/openstackclient/tests/identity/v3/test_user.py @@ -320,6 +320,68 @@ class TestUserCreate(TestUser): ) self.assertEqual(datalist, data) + def test_user_create_project_domain(self): + # Return the new project + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT_2), + loaded=True, + ) + # Set up to return an updated user + USER_2 = copy.deepcopy(identity_fakes.USER) + USER_2['default_project_id'] = identity_fakes.PROJECT_2['id'] + self.users_mock.create.return_value = fakes.FakeResource( + None, + USER_2, + loaded=True, + ) + + arglist = [ + '--project', identity_fakes.PROJECT_2['name'], + '--project-domain', identity_fakes.PROJECT_2['domain_id'], + identity_fakes.user_name, + ] + verifylist = [ + ('project', identity_fakes.PROJECT_2['name']), + ('project_domain', identity_fakes.PROJECT_2['domain_id']), + ('enable', False), + ('disable', False), + ('name', identity_fakes.user_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = { + 'name': identity_fakes.user_name, + 'default_project': identity_fakes.PROJECT_2['id'], + 'description': None, + 'domain': None, + 'email': None, + 'enabled': True, + 'password': None, + } + # UserManager.create(name=, domain=, project=, password=, email=, + # description=, enabled=, default_project=) + self.users_mock.create.assert_called_with( + **kwargs + ) + + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') + self.assertEqual(collist, columns) + datalist = ( + identity_fakes.PROJECT_2['id'], + identity_fakes.domain_id, + identity_fakes.user_email, + True, + identity_fakes.user_id, + identity_fakes.user_name, + ) + self.assertEqual(datalist, data) + def test_user_create_domain(self): arglist = [ '--domain', identity_fakes.domain_name, @@ -894,6 +956,39 @@ class TestUserSet(TestUser): **kwargs ) + def test_user_set_project_domain(self): + arglist = [ + '--project', identity_fakes.project_id, + '--project-domain', identity_fakes.domain_id, + identity_fakes.user_name, + ] + verifylist = [ + ('name', None), + ('password', None), + ('email', None), + ('project', identity_fakes.project_id), + ('project_domain', identity_fakes.domain_id), + ('enable', False), + ('disable', False), + ('user', identity_fakes.user_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = { + 'enabled': True, + 'default_project': identity_fakes.project_id, + } + # UserManager.update(user, name=, domain=, project=, password=, + # email=, description=, enabled=, default_project=) + self.users_mock.update.assert_called_with( + identity_fakes.user_id, + **kwargs + ) + def test_user_set_enable(self): arglist = [ '--enable', diff --git a/openstackclient/tests/test_shell.py b/openstackclient/tests/test_shell.py index 0b4ff685..e2f0580b 100644 --- a/openstackclient/tests/test_shell.py +++ b/openstackclient/tests/test_shell.py @@ -39,7 +39,7 @@ DEFAULT_REGION_NAME = "ZZ9_Plural_Z_Alpha" DEFAULT_TOKEN = "token" DEFAULT_SERVICE_URL = "http://127.0.0.1:8771/v3.0/" DEFAULT_AUTH_PLUGIN = "v2password" -DEFAULT_ENDPOINT_TYPE = "internal" +DEFAULT_INTERFACE = "internal" DEFAULT_COMPUTE_API_VERSION = "2" DEFAULT_IDENTITY_API_VERSION = "2" @@ -63,7 +63,7 @@ CLOUD_1 = { }, 'region_name': 'occ-cloud', 'donut': 'glazed', - 'endpoint_type': 'public', + 'interface': 'public', } } } @@ -107,7 +107,7 @@ global_options = { '--os-default-domain': (DEFAULT_DOMAIN_NAME, True, True), '--os-cacert': ('/dev/null', True, True), '--timing': (True, True, False), - '--os-endpoint-type': (DEFAULT_ENDPOINT_TYPE, True, True) + '--os-interface': (DEFAULT_INTERFACE, True, True) } auth_options = { @@ -127,7 +127,7 @@ auth_options = { '--os-auth-type': ("v2password", True, True), '--os-token': (DEFAULT_TOKEN, True, True), '--os-url': (DEFAULT_SERVICE_URL, True, True), - '--os-endpoint-type': (DEFAULT_ENDPOINT_TYPE, True, True), + '--os-interface': (DEFAULT_INTERFACE, True, True), } @@ -616,7 +616,7 @@ class TestShellCli(TestShell): ) self.assertEqual( 'public', - _shell.cloud.config['endpoint_type'], + _shell.cloud.config['interface'], ) @mock.patch("os_client_config.config.OpenStackConfig._load_vendor_file") diff --git a/openstackclient/tests/volume/v1/test_qos_specs.py b/openstackclient/tests/volume/v1/test_qos_specs.py index 226fe673..c2e6c0af 100644 --- a/openstackclient/tests/volume/v1/test_qos_specs.py +++ b/openstackclient/tests/volume/v1/test_qos_specs.py @@ -56,7 +56,7 @@ class TestQosAssociate(TestQos): volume_fakes.type_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('volume_type', volume_fakes.type_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -210,7 +210,7 @@ class TestQosDelete(TestQos): volume_fakes.qos_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id) + ('qos_specs', [volume_fakes.qos_id]) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -223,7 +223,7 @@ class TestQosDelete(TestQos): volume_fakes.qos_name ] verifylist = [ - ('qos_specs', volume_fakes.qos_name) + ('qos_specs', [volume_fakes.qos_name]) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -255,7 +255,7 @@ class TestQosDisassociate(TestQos): '--volume-type', volume_fakes.type_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('volume_type', volume_fakes.type_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -278,7 +278,7 @@ class TestQosDisassociate(TestQos): '--all' ] verifylist = [ - ('qos_specs', volume_fakes.qos_id) + ('qos_spec', volume_fakes.qos_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -351,7 +351,7 @@ class TestQosSet(TestQos): '--property', 'iops=9001' ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('property', volume_fakes.qos_specs) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -386,7 +386,7 @@ class TestQosShow(TestQos): volume_fakes.qos_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id) + ('qos_spec', volume_fakes.qos_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -434,7 +434,7 @@ class TestQosUnset(TestQos): ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('property', ['iops', 'foo']) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/volume/v2/test_qos_specs.py b/openstackclient/tests/volume/v2/test_qos_specs.py index 6a550988..4222ed07 100644 --- a/openstackclient/tests/volume/v2/test_qos_specs.py +++ b/openstackclient/tests/volume/v2/test_qos_specs.py @@ -56,7 +56,7 @@ class TestQosAssociate(TestQos): volume_fakes.type_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('volume_type', volume_fakes.type_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -210,7 +210,7 @@ class TestQosDelete(TestQos): volume_fakes.qos_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id) + ('qos_specs', [volume_fakes.qos_id]) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -223,7 +223,7 @@ class TestQosDelete(TestQos): volume_fakes.qos_name ] verifylist = [ - ('qos_specs', volume_fakes.qos_name) + ('qos_specs', [volume_fakes.qos_name]) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -255,7 +255,7 @@ class TestQosDisassociate(TestQos): '--volume-type', volume_fakes.type_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('volume_type', volume_fakes.type_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -278,7 +278,7 @@ class TestQosDisassociate(TestQos): '--all' ] verifylist = [ - ('qos_specs', volume_fakes.qos_id) + ('qos_spec', volume_fakes.qos_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -351,7 +351,7 @@ class TestQosSet(TestQos): '--property', 'iops=9001' ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('property', volume_fakes.qos_specs) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -386,7 +386,7 @@ class TestQosShow(TestQos): volume_fakes.qos_id ] verifylist = [ - ('qos_specs', volume_fakes.qos_id) + ('qos_spec', volume_fakes.qos_id) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -434,7 +434,7 @@ class TestQosUnset(TestQos): ] verifylist = [ - ('qos_specs', volume_fakes.qos_id), + ('qos_spec', volume_fakes.qos_id), ('property', ['iops', 'foo']) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/volume/client.py b/openstackclient/volume/client.py index 965c42ec..093178e3 100644 --- a/openstackclient/volume/client.py +++ b/openstackclient/volume/client.py @@ -53,9 +53,8 @@ def make_client(instance): extensions = [extension.Extension('list_extensions', list_extensions)] - # Remember endpoint_type only if it is set - kwargs = utils.build_kwargs_dict('endpoint_type', - instance._endpoint_type) + # Remember interface only if it is set + kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface) client = volume_client( session=instance.session, diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py index eacb9706..8e909e3d 100644 --- a/openstackclient/volume/v1/qos_specs.py +++ b/openstackclient/volume/v1/qos_specs.py @@ -34,8 +34,8 @@ class AssociateQos(command.Command): def get_parser(self, prog_name): parser = super(AssociateQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) parser.add_argument( @@ -48,12 +48,12 @@ class AssociateQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) volume_type = utils.find_resource(volume_client.volume_types, parsed_args.volume_type) - volume_client.qos_specs.associate(qos_specs.id, volume_type.id) + volume_client.qos_specs.associate(qos_spec.id, volume_type.id) return @@ -97,9 +97,9 @@ class CreateQos(show.ShowOne): if parsed_args.property: specs.update(parsed_args.property) - qos_specs = volume_client.qos_specs.create(parsed_args.name, specs) + qos_spec = volume_client.qos_specs.create(parsed_args.name, specs) - return zip(*sorted(six.iteritems(qos_specs._info))) + return zip(*sorted(six.iteritems(qos_spec._info))) class DeleteQos(command.Command): @@ -111,19 +111,18 @@ class DeleteQos(command.Command): parser = super(DeleteQos, self).get_parser(prog_name) parser.add_argument( 'qos_specs', - metavar='<qos-specs>', - help='QoS specification to delete (name or ID)', + metavar='<qos-spec>', + nargs="+", + help='QoS specification(s) to delete (name or ID)', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) - - volume_client.qos_specs.delete(qos_specs.id) - + for qos in parsed_args.qos_specs: + qos_spec = utils.find_resource(volume_client.qos_specs, qos) + volume_client.qos_specs.delete(qos_spec.id) return @@ -135,8 +134,8 @@ class DisassociateQos(command.Command): def get_parser(self, prog_name): parser = super(DisassociateQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) volume_type_group = parser.add_mutually_exclusive_group() @@ -157,15 +156,15 @@ class DisassociateQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) if parsed_args.volume_type: volume_type = utils.find_resource(volume_client.volume_types, parsed_args.volume_type) - volume_client.qos_specs.disassociate(qos_specs.id, volume_type.id) + volume_client.qos_specs.disassociate(qos_spec.id, volume_type.id) elif parsed_args.all: - volume_client.qos_specs.disassociate_all(qos_specs.id) + volume_client.qos_specs.disassociate_all(qos_spec.id) return @@ -206,8 +205,8 @@ class SetQos(command.Command): def get_parser(self, prog_name): parser = super(SetQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) parser.add_argument( @@ -222,11 +221,11 @@ class SetQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) if parsed_args.property: - volume_client.qos_specs.set_keys(qos_specs.id, + volume_client.qos_specs.set_keys(qos_spec.id, parsed_args.property) else: self.app.log.error("No changes requested\n") @@ -242,8 +241,8 @@ class ShowQos(show.ShowOne): def get_parser(self, prog_name): parser = super(ShowQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to display (name or ID)', ) return parser @@ -251,19 +250,19 @@ class ShowQos(show.ShowOne): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) - qos_associations = volume_client.qos_specs.get_associations(qos_specs) + qos_associations = volume_client.qos_specs.get_associations(qos_spec) if qos_associations: associations = [association.name for association in qos_associations] - qos_specs._info.update({ + qos_spec._info.update({ 'associations': utils.format_list(associations) }) - qos_specs._info.update({'specs': utils.format_dict(qos_specs.specs)}) + qos_spec._info.update({'specs': utils.format_dict(qos_spec.specs)}) - return zip(*sorted(six.iteritems(qos_specs._info))) + return zip(*sorted(six.iteritems(qos_spec._info))) class UnsetQos(command.Command): @@ -274,8 +273,8 @@ class UnsetQos(command.Command): def get_parser(self, prog_name): parser = super(UnsetQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) parser.add_argument( @@ -291,11 +290,11 @@ class UnsetQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) if parsed_args.property: - volume_client.qos_specs.unset_keys(qos_specs.id, + volume_client.qos_specs.unset_keys(qos_spec.id, parsed_args.property) else: self.app.log.error("No changes requested\n") diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index 5ec2b3c5..e81efb5a 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -263,6 +263,7 @@ class UnsetSnapshot(command.Command): default=[], help='Property to remove from snapshot ' '(repeat to remove multiple values)', + required=True, ) return parser diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index ad9671e3..884611ec 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -437,6 +437,7 @@ class UnsetVolume(command.Command): default=[], help='Property to remove from volume ' '(repeat option to remove multiple properties)', + required=True, ) return parser diff --git a/openstackclient/volume/v1/type.py b/openstackclient/volume/v1/volume_type.py index 46d1828b..d5c617b2 100644 --- a/openstackclient/volume/v1/type.py +++ b/openstackclient/volume/v1/volume_type.py @@ -166,6 +166,7 @@ class UnsetVolumeType(command.Command): default=[], help='Property to remove from volume type ' '(repeat option to remove multiple properties)', + required=True, ) return parser @@ -182,3 +183,27 @@ class UnsetVolumeType(command.Command): else: self.app.log.error("No changes requested\n") return + + +class ShowVolumeType(show.ShowOne): + """Display volume type details""" + + log = logging.getLogger(__name__ + ".ShowVolumeType") + + def get_parser(self, prog_name): + parser = super(ShowVolumeType, self).get_parser(prog_name) + parser.add_argument( + "volume_type", + metavar="<volume-type>", + help="Volume type to display (name or ID)" + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action: (%s)", parsed_args) + volume_client = self.app.client_manager.volume + volume_type = utils.find_resource( + volume_client.volume_types, parsed_args.volume_type) + properties = utils.format_dict(volume_type._info.pop('extra_specs')) + volume_type._info.update({'properties': properties}) + return zip(*sorted(six.iteritems(volume_type._info))) diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index 7f02fa4a..ac78ca15 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -34,8 +34,8 @@ class AssociateQos(command.Command): def get_parser(self, prog_name): parser = super(AssociateQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) parser.add_argument( @@ -48,12 +48,12 @@ class AssociateQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) volume_type = utils.find_resource(volume_client.volume_types, parsed_args.volume_type) - volume_client.qos_specs.associate(qos_specs.id, volume_type.id) + volume_client.qos_specs.associate(qos_spec.id, volume_type.id) return @@ -97,9 +97,9 @@ class CreateQos(show.ShowOne): if parsed_args.property: specs.update(parsed_args.property) - qos_specs = volume_client.qos_specs.create(parsed_args.name, specs) + qos_spec = volume_client.qos_specs.create(parsed_args.name, specs) - return zip(*sorted(six.iteritems(qos_specs._info))) + return zip(*sorted(six.iteritems(qos_spec._info))) class DeleteQos(command.Command): @@ -111,19 +111,18 @@ class DeleteQos(command.Command): parser = super(DeleteQos, self).get_parser(prog_name) parser.add_argument( 'qos_specs', - metavar='<qos-specs>', - help='QoS specification to delete (name or ID)', + metavar='<qos-spec>', + nargs="+", + help='QoS specification(s) to delete (name or ID)', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) - - volume_client.qos_specs.delete(qos_specs.id) - + for qos in parsed_args.qos_specs: + qos_spec = utils.find_resource(volume_client.qos_specs, qos) + volume_client.qos_specs.delete(qos_spec.id) return @@ -135,8 +134,8 @@ class DisassociateQos(command.Command): def get_parser(self, prog_name): parser = super(DisassociateQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) volume_type_group = parser.add_mutually_exclusive_group() @@ -157,15 +156,15 @@ class DisassociateQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) if parsed_args.volume_type: volume_type = utils.find_resource(volume_client.volume_types, parsed_args.volume_type) - volume_client.qos_specs.disassociate(qos_specs.id, volume_type.id) + volume_client.qos_specs.disassociate(qos_spec.id, volume_type.id) elif parsed_args.all: - volume_client.qos_specs.disassociate_all(qos_specs.id) + volume_client.qos_specs.disassociate_all(qos_spec.id) return @@ -206,8 +205,8 @@ class SetQos(command.Command): def get_parser(self, prog_name): parser = super(SetQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) parser.add_argument( @@ -222,11 +221,11 @@ class SetQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) if parsed_args.property: - volume_client.qos_specs.set_keys(qos_specs.id, + volume_client.qos_specs.set_keys(qos_spec.id, parsed_args.property) else: self.app.log.error("No changes requested\n") @@ -242,8 +241,8 @@ class ShowQos(show.ShowOne): def get_parser(self, prog_name): parser = super(ShowQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to display (name or ID)', ) return parser @@ -251,19 +250,19 @@ class ShowQos(show.ShowOne): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) - qos_associations = volume_client.qos_specs.get_associations(qos_specs) + qos_associations = volume_client.qos_specs.get_associations(qos_spec) if qos_associations: associations = [association.name for association in qos_associations] - qos_specs._info.update({ + qos_spec._info.update({ 'associations': utils.format_list(associations) }) - qos_specs._info.update({'specs': utils.format_dict(qos_specs.specs)}) + qos_spec._info.update({'specs': utils.format_dict(qos_spec.specs)}) - return zip(*sorted(six.iteritems(qos_specs._info))) + return zip(*sorted(six.iteritems(qos_spec._info))) class UnsetQos(command.Command): @@ -274,8 +273,8 @@ class UnsetQos(command.Command): def get_parser(self, prog_name): parser = super(UnsetQos, self).get_parser(prog_name) parser.add_argument( - 'qos_specs', - metavar='<qos-specs>', + 'qos_spec', + metavar='<qos-spec>', help='QoS specification to modify (name or ID)', ) parser.add_argument( @@ -291,11 +290,11 @@ class UnsetQos(command.Command): def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - qos_specs = utils.find_resource(volume_client.qos_specs, - parsed_args.qos_specs) + qos_spec = utils.find_resource(volume_client.qos_specs, + parsed_args.qos_spec) if parsed_args.property: - volume_client.qos_specs.unset_keys(qos_specs.id, + volume_client.qos_specs.unset_keys(qos_spec.id, parsed_args.property) else: self.app.log.error("No changes requested\n") |
