diff options
Diffstat (limited to 'openstackclient')
38 files changed, 512 insertions, 201 deletions
diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py index edabf65e..dce19725 100644 --- a/openstackclient/common/clientmanager.py +++ b/openstackclient/common/clientmanager.py @@ -191,6 +191,26 @@ class ClientManager(object): self._auth_ref = self.auth.get_auth_ref(self.session) return self._auth_ref + def is_network_endpoint_enabled(self): + """Check if the network endpoint is enabled""" + # Trigger authentication necessary to determine if the network + # endpoint is enabled. + if self.auth_ref: + service_catalog = self.auth_ref.service_catalog + else: + service_catalog = None + # Assume that the network endpoint is enabled. + network_endpoint_enabled = True + if service_catalog: + if 'network' in service_catalog.get_endpoints(): + LOG.debug("Network endpoint in service catalog") + else: + LOG.debug("No network endpoint in service catalog") + network_endpoint_enabled = False + else: + LOG.debug("No service catalog, assuming network endpoint enabled") + return network_endpoint_enabled + def get_endpoint_for_service_type(self, service_type, region_name=None, interface='public'): """Return the endpoint URL for the service type.""" diff --git a/openstackclient/common/commandmanager.py b/openstackclient/common/commandmanager.py index b34bf7d6..b809d63a 100644 --- a/openstackclient/common/commandmanager.py +++ b/openstackclient/common/commandmanager.py @@ -15,15 +15,11 @@ """Modify cliff.CommandManager""" -import logging import pkg_resources import cliff.commandmanager -LOG = logging.getLogger(__name__) - - class CommandManager(cliff.commandmanager.CommandManager): """Add additional functionality to cliff.CommandManager diff --git a/openstackclient/common/extension.py b/openstackclient/common/extension.py index 8825b491..d1ae208d 100644 --- a/openstackclient/common/extension.py +++ b/openstackclient/common/extension.py @@ -49,7 +49,7 @@ class ListExtension(lister.Lister): '--volume', action='store_true', default=False, - help='List extensions for the Volume API') + help='List extensions for the Block Storage API') parser.add_argument( '--long', action='store_true', @@ -95,7 +95,7 @@ class ListExtension(lister.Lister): try: data += volume_client.list_extensions.show_all() except Exception: - message = "Extensions list not supported by Volume API" + message = "Extensions list not supported by Block Storage API" self.log.warning(message) # Resource classes for the above diff --git a/openstackclient/common/limits.py b/openstackclient/common/limits.py index 582f70c5..57703670 100644 --- a/openstackclient/common/limits.py +++ b/openstackclient/common/limits.py @@ -25,7 +25,7 @@ from openstackclient.identity import common as identity_common class ShowLimits(lister.Lister): - """Show compute and volume limits""" + """Show compute and block storage limits""" log = logging.getLogger(__name__ + '.ShowLimits') diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py index 42630d91..096c995b 100644 --- a/openstackclient/common/utils.py +++ b/openstackclient/common/utils.py @@ -154,14 +154,15 @@ def format_dict(data): return output[:-2] -def format_list(data): +def format_list(data, separator=', '): """Return a formatted strings :param data: a list of strings - :rtype: a string formatted to a,b,c + :param separator: the separator to use between strings (default: ', ') + :rtype: a string formatted based on separator """ - return ', '.join(sorted(data)) + return separator.join(sorted(data)) def get_field(item, field): @@ -258,10 +259,6 @@ def sort_items(items, sort_str): return items -def string_to_bool(arg): - return arg.strip().lower() in ('t', 'true', 'yes', '1') - - def env(*vars, **kwargs): """Search for the first defined of possibly many env vars diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py index e3f542b5..6395e102 100644 --- a/openstackclient/compute/v2/security_group.py +++ b/openstackclient/compute/v2/security_group.py @@ -62,6 +62,23 @@ def _xform_security_group_rule(sgroup): return info +def _xform_and_trim_security_group_rule(sgroup): + info = _xform_security_group_rule(sgroup) + # Trim parent security group ID since caller has this information. + info.pop('parent_group_id', None) + # Trim keys with empty string values. + keys_to_trim = [ + 'ip_protocol', + 'ip_range', + 'port_range', + 'remote_security_group', + ] + for key in keys_to_trim: + if key in info and not info[key]: + info.pop(key) + return info + + class CreateSecurityGroup(show.ShowOne): """Create a new security group""" @@ -276,6 +293,7 @@ class ListSecurityGroupRule(lister.Lister): parser.add_argument( 'group', metavar='<group>', + nargs='?', help='List all rules in this security group (name or ID)', ) return parser @@ -284,26 +302,35 @@ class ListSecurityGroupRule(lister.Lister): self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute - group = utils.find_resource( - compute_client.security_groups, - parsed_args.group, + columns = column_headers = ( + "ID", + "IP Protocol", + "IP Range", + "Port Range", + "Remote Security Group", ) + rules_to_list = [] + if parsed_args.group: + group = utils.find_resource( + compute_client.security_groups, + parsed_args.group, + ) + rules_to_list = group.rules + else: + columns = columns + ('parent_group_id',) + column_headers = column_headers + ('Security Group',) + for group in compute_client.security_groups.list(): + rules_to_list.extend(group.rules) + # Argh, the rules are not Resources... rules = [] - for rule in group.rules: + for rule in rules_to_list: rules.append(security_group_rules.SecurityGroupRule( compute_client.security_group_rules, _xform_security_group_rule(rule), )) - columns = column_headers = ( - "ID", - "IP Protocol", - "IP Range", - "Port Range", - "Remote Security Group", - ) return (column_headers, (utils.get_item_properties( s, columns, @@ -386,11 +413,12 @@ class ShowSecurityGroup(show.ShowOne): )._info) rules = [] for r in info['rules']: - rules.append(utils.format_dict(_xform_security_group_rule(r))) + formatted_rule = _xform_and_trim_security_group_rule(r) + rules.append(utils.format_dict(formatted_rule)) # Format rules into a list of strings info.update( - {'rules': rules} + {'rules': utils.format_list(rules, separator='\n')} ) # Map 'tenant_id' column to 'project_id' info.update( diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index be0ad8cb..7afd18f2 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -257,10 +257,6 @@ class CreateServer(show.ShowOne): log = logging.getLogger(__name__ + '.CreateServer') - def _is_neutron_enabled(self): - service_catalog = self.app.client_manager.auth_ref.service_catalog - return 'network' in service_catalog.get_endpoints() - def get_parser(self, prog_name): parser = super(CreateServer, self).get_parser(prog_name) parser.add_argument( @@ -460,8 +456,6 @@ class CreateServer(show.ShowOne): block_device_mapping.update({dev_key: block_volume}) nics = [] - if parsed_args.nic: - neutron_enabled = self._is_neutron_enabled() for nic_str in parsed_args.nic: nic_info = {"net-id": "", "v4-fixed-ip": "", "v6-fixed-ip": "", "port-id": ""} @@ -471,7 +465,7 @@ class CreateServer(show.ShowOne): msg = _("either net-id or port-id should be specified " "but not both") raise exceptions.CommandError(msg) - if neutron_enabled: + if self.app.client_manager.is_network_endpoint_enabled(): network_client = self.app.client_manager.network if nic_info["net-id"]: net = network_client.find_network( @@ -489,7 +483,7 @@ class CreateServer(show.ShowOne): ).id if nic_info["port-id"]: msg = _("can't create server with port specified " - "since neutron not enabled") + "since network endpoint not enabled") raise exceptions.CommandError(msg) nics.append(nic_info) diff --git a/openstackclient/compute/v2/service.py b/openstackclient/compute/v2/service.py index 0a3a5fe4..af3e940a 100644 --- a/openstackclient/compute/v2/service.py +++ b/openstackclient/compute/v2/service.py @@ -100,7 +100,7 @@ class SetService(command.Command): "--enable", dest="enabled", default=True, - help="Enable a service", + help="Enable a service (default)", action="store_true") enabled_group.add_argument( "--disable", diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py index 065f0adf..4330c79c 100644 --- a/openstackclient/identity/v2_0/project.py +++ b/openstackclient/identity/v2_0/project.py @@ -282,4 +282,60 @@ class ShowProject(show.ShowOne): # TODO(stevemar): Remove the line below when we support multitenancy info.pop('parent_id', None) + + # NOTE(stevemar): Property handling isn't really supported in Keystone + # and needs a lot of extra handling. Let's reserve the properties that + # the API has and handle the extra top level properties. + reserved = ('name', 'id', 'enabled', 'description') + properties = {} + for k, v in info.items(): + if k not in reserved: + # If a key is not in `reserved` it's a property, pop it + info.pop(k) + # If a property has been "unset" it's `None`, so don't show it + if v is not None: + properties[k] = v + + info['properties'] = utils.format_dict(properties) return zip(*sorted(six.iteritems(info))) + + +class UnsetProject(command.Command): + """Unset project properties""" + + log = logging.getLogger(__name__ + '.UnsetProject') + + def get_parser(self, prog_name): + parser = super(UnsetProject, self).get_parser(prog_name) + parser.add_argument( + 'project', + metavar='<project>', + help=_('Project to modify (name or ID)'), + ) + parser.add_argument( + '--property', + metavar='<key>', + action='append', + default=[], + help=_('Unset a project property ' + '(repeat option to unset multiple properties)'), + required=True, + ) + return parser + + @utils.log_method(log) + def take_action(self, parsed_args): + identity_client = self.app.client_manager.identity + project = utils.find_resource( + identity_client.tenants, + parsed_args.project, + ) + if not parsed_args.property: + self.app.log.error("No changes requested\n") + else: + kwargs = project._info + for key in parsed_args.property: + if key in kwargs: + kwargs[key] = None + identity_client.tenants.update(project.id, **kwargs) + return diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py index f87105dd..22745aa4 100644 --- a/openstackclient/identity/v3/project.py +++ b/openstackclient/identity/v3/project.py @@ -283,16 +283,12 @@ class SetProject(command.Command): and not parsed_args.disable): return - project = utils.find_resource( - identity_client.projects, - parsed_args.project, - ) + project = common.find_project(identity_client, parsed_args.project, + parsed_args.domain) kwargs = {} if parsed_args.name: kwargs['name'] = parsed_args.name - if parsed_args.domain: - kwargs['domain'] = parsed_args.domain if parsed_args.description: kwargs['description'] = parsed_args.description if parsed_args.enable: diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py index eaef8f05..43a116cb 100644 --- a/openstackclient/identity/v3/user.py +++ b/openstackclient/identity/v3/user.py @@ -392,14 +392,41 @@ class SetPasswordUser(command.Command): metavar='<new-password>', help='New user password' ) + parser.add_argument( + '--original-password', + metavar='<original-password>', + help='Original user password' + ) return parser @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity - current_password = utils.get_password( - self.app.stdin, prompt="Current Password:", confirm=False) + # FIXME(gyee): there are two scenarios: + # + # 1. user update password for himself + # 2. admin update password on behalf of the user. This is an unlikely + # scenario because that will require admin knowing the user's + # original password which is forbidden under most security + # policies. + # + # Of the two scenarios above, user either authenticate using its + # original password or an authentication token. For scenario #1, + # if user is authenticating with its original password (i.e. passing + # --os-password argument), we can just make use of it instead of using + # --original-password or prompting. For scenario #2, admin will need + # to specify --original-password option or this won't work because + # --os-password is the admin's own password. In the future if we stop + # supporting scenario #2 then we can just do this. + # + # current_password = (parsed_args.original_password or + # self.app.cloud.password) + # + current_password = parsed_args.original_password + if current_password is None: + current_password = utils.get_password( + self.app.stdin, prompt="Current Password:", confirm=False) password = parsed_args.password if password is None: diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py index 4ebc8f93..0382501e 100644 --- a/openstackclient/image/v1/image.py +++ b/openstackclient/image/v1/image.py @@ -679,8 +679,6 @@ class SetImage(command.Command): kwargs['data'] != sys.stdin): kwargs['data'].close() - return - class ShowImage(show.ShowOne): """Display image details""" diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 1fcb92d9..ad536ba2 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -220,6 +220,7 @@ class CreateImage(show.ShowOne): help="Set a tag on this image " "(repeat option to set multiple tags)", ) + common.add_project_domain_option_to_parser(parser) for deadopt in self.deadopts: parser.add_argument( "--%s" % deadopt, @@ -231,6 +232,7 @@ class CreateImage(show.ShowOne): def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) + identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: @@ -285,6 +287,13 @@ class CreateImage(show.ShowOne): self.log.warning("Failed to get an image file.") return {}, {} + if parsed_args.owner: + kwargs['owner'] = common.find_project( + identity_client, + parsed_args.owner, + parsed_args.project_domain, + ).id + # If a volume is specified. if parsed_args.volume: volume_client = self.app.client_manager.volume @@ -704,6 +713,7 @@ class SetImage(command.Command): action="store_true", help="Activate the image", ) + common.add_project_domain_option_to_parser(parser) for deadopt in self.deadopts: parser.add_argument( "--%s" % deadopt, @@ -715,6 +725,7 @@ class SetImage(command.Command): def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) + identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: @@ -779,6 +790,13 @@ class SetImage(command.Command): # Tags should be extended, but duplicates removed kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags))) + if parsed_args.owner: + kwargs['owner'] = common.find_project( + identity_client, + parsed_args.owner, + parsed_args.project_domain, + ).id + try: image = image_client.images.update(image.id, **kwargs) except Exception as e: diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index 15f4592b..38dff8d9 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -39,6 +39,17 @@ _formatters = { } +def _get_columns(item): + columns = item.keys() + if 'tenant_id' in columns: + columns.remove('tenant_id') + columns.append('project_id') + if 'router:external' in columns: + columns.remove('router:external') + columns.append('router_external') + return tuple(sorted(columns)) + + class CreateNetwork(show.ShowOne): """Create new network""" @@ -91,9 +102,9 @@ class CreateNetwork(show.ShowOne): client = self.app.client_manager.network body = self.get_body(parsed_args) obj = client.create_network(**body) - columns = sorted(obj.keys()) + columns = _get_columns(obj) data = utils.get_item_properties(obj, columns, formatters=_formatters) - return (tuple(columns), data) + return (columns, data) def get_body(self, parsed_args): body = {'name': str(parsed_args.name), @@ -290,6 +301,6 @@ class ShowNetwork(show.ShowOne): self.log.debug('take_action(%s)' % parsed_args) client = self.app.client_manager.network obj = client.find_network(parsed_args.identifier, ignore_missing=False) - columns = sorted(obj.keys()) + columns = _get_columns(obj) data = utils.get_item_properties(obj, columns, formatters=_formatters) - return (tuple(columns), data) + return (columns, data) diff --git a/openstackclient/object/client.py b/openstackclient/object/client.py index e7587802..3af6f8a0 100644 --- a/openstackclient/object/client.py +++ b/openstackclient/object/client.py @@ -15,13 +15,9 @@ """Object client""" -import logging - from openstackclient.api import object_store_v1 from openstackclient.common import utils -LOG = logging.getLogger(__name__) - DEFAULT_API_VERSION = '1' API_VERSION_OPTION = 'os_object_api_version' API_NAME = 'object_store' diff --git a/openstackclient/tests/common/test_clientmanager.py b/openstackclient/tests/common/test_clientmanager.py index 29cc59ed..523f79a3 100644 --- a/openstackclient/tests/common/test_clientmanager.py +++ b/openstackclient/tests/common/test_clientmanager.py @@ -77,6 +77,9 @@ class TestClientManager(utils.TestCase): self.requests = self.useFixture(fixture.Fixture()) # fake v2password token retrieval self.stub_auth(json=fakes.TEST_RESPONSE_DICT) + # fake token and token_endpoint retrieval + self.stub_auth(json=fakes.TEST_RESPONSE_DICT, + url='/'.join([fakes.AUTH_URL, 'v2.0/tokens'])) # fake v3password token retrieval self.stub_auth(json=fakes.TEST_RESPONSE_DICT_V3, url='/'.join([fakes.AUTH_URL, 'auth/tokens'])) @@ -99,6 +102,7 @@ class TestClientManager(utils.TestCase): verify=True ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( fakes.AUTH_URL, @@ -114,6 +118,7 @@ class TestClientManager(utils.TestCase): ) self.assertFalse(client_manager._insecure) self.assertTrue(client_manager._verify) + self.assertTrue(client_manager.is_network_endpoint_enabled()) def test_client_manager_token(self): @@ -131,6 +136,7 @@ class TestClientManager(utils.TestCase): verify=True ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( fakes.AUTH_URL, @@ -150,6 +156,7 @@ class TestClientManager(utils.TestCase): ) self.assertFalse(client_manager._insecure) self.assertTrue(client_manager._verify) + self.assertTrue(client_manager.is_network_endpoint_enabled()) def test_client_manager_password(self): @@ -166,6 +173,7 @@ class TestClientManager(utils.TestCase): verify=False, ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( fakes.AUTH_URL, @@ -195,6 +203,28 @@ class TestClientManager(utils.TestCase): dir(SERVICE_CATALOG), dir(client_manager.auth_ref.service_catalog), ) + self.assertTrue(client_manager.is_network_endpoint_enabled()) + + def test_client_manager_network_endpoint_disabled(self): + + client_manager = clientmanager.ClientManager( + cli_options=FakeOptions( + auth=dict( + auth_url=fakes.AUTH_URL, + username=fakes.USERNAME, + password=fakes.PASSWORD, + project_name=fakes.PROJECT_NAME, + ), + auth_type='v3password', + ), + api_version={"identity": "3"}, + verify=False, + ) + client_manager.setup_auth() + client_manager.auth_ref + + # v3 fake doesn't have network endpoint. + self.assertFalse(client_manager.is_network_endpoint_enabled()) def stub_auth(self, json=None, url=None, verb=None, **kwargs): subject_token = fakes.AUTH_TOKEN @@ -229,10 +259,12 @@ class TestClientManager(utils.TestCase): verify='cafile', ) client_manager.setup_auth() + client_manager.auth_ref self.assertFalse(client_manager._insecure) self.assertTrue(client_manager._verify) self.assertEqual('cafile', client_manager._cacert) + self.assertTrue(client_manager.is_network_endpoint_enabled()) def _select_auth_plugin(self, auth_params, api_version, auth_plugin_name): auth_params['auth_type'] = auth_plugin_name @@ -243,6 +275,7 @@ class TestClientManager(utils.TestCase): verify=True ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( auth_plugin_name, diff --git a/openstackclient/tests/common/test_logs.py b/openstackclient/tests/common/test_logs.py index fe054a3b..a319533a 100644 --- a/openstackclient/tests/common/test_logs.py +++ b/openstackclient/tests/common/test_logs.py @@ -137,7 +137,7 @@ class TestLogConfigurator(utils.TestCase): self.cliff_log.setLevel.assert_called_with(logging.ERROR) self.stevedore_log.setLevel.assert_called_with(logging.ERROR) self.iso8601_log.setLevel.assert_called_with(logging.ERROR) - self.assertEqual(False, configurator.dump_trace) + self.assertFalse(configurator.dump_trace) @mock.patch('logging.getLogger') @mock.patch('openstackclient.common.logs.set_warning_filter') @@ -149,7 +149,7 @@ class TestLogConfigurator(utils.TestCase): warning_filter.assert_called_with(logging.DEBUG) self.requests_log.setLevel.assert_called_with(logging.DEBUG) - self.assertEqual(True, configurator.dump_trace) + self.assertTrue(configurator.dump_trace) @mock.patch('logging.FileHandler') @mock.patch('logging.getLogger') @@ -199,4 +199,4 @@ class TestLogConfigurator(utils.TestCase): self.root_logger.addHandler.assert_called_with(file_logger) file_logger.setFormatter.assert_called_with(mock_formatter) file_logger.setLevel.assert_called_with(logging.INFO) - self.assertEqual(False, configurator.dump_trace) + self.assertFalse(configurator.dump_trace) diff --git a/openstackclient/tests/common/test_parseractions.py b/openstackclient/tests/common/test_parseractions.py index b75c4814..0109a3f3 100644 --- a/openstackclient/tests/common/test_parseractions.py +++ b/openstackclient/tests/common/test_parseractions.py @@ -20,34 +20,14 @@ from openstackclient.tests import utils class TestKeyValueAction(utils.TestCase): - def test_good_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--property', - metavar='<key=value>', - action=parseractions.KeyValueAction, - help='Property to store for this volume ' - '(repeat option to set multiple properties)', - ) - - results = parser.parse_args([ - '--property', 'red=', - '--property', 'green=100%', - '--property', 'blue=50%', - ]) - actual = getattr(results, 'property', {}) - # All should pass through unmolested - expect = {'red': '', 'green': '100%', 'blue': '50%'} - self.assertDictEqual(expect, actual) + def setUp(self): + super(TestKeyValueAction, self).setUp() - def test_default_values(self): - parser = argparse.ArgumentParser() + self.parser = argparse.ArgumentParser() # Set up our typical usage - parser.add_argument( + self.parser.add_argument( '--property', metavar='<key=value>', action=parseractions.KeyValueAction, @@ -56,84 +36,55 @@ class TestKeyValueAction(utils.TestCase): '(repeat option to set multiple properties)', ) - results = parser.parse_args([ + def test_good_values(self): + results = self.parser.parse_args([ '--property', 'red=', '--property', 'green=100%', '--property', 'blue=50%', ]) actual = getattr(results, 'property', {}) - # Verify green default is changed, format default is unchanged + # All should pass through unmolested expect = {'red': '', 'green': '100%', 'blue': '50%', 'format': '#rgb'} self.assertDictEqual(expect, actual) def test_error_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--property', - metavar='<key=value>', - action=parseractions.KeyValueAction, - default={'green': '20%', 'blue': '40%'}, - help='Property to store for this volume ' - '(repeat option to set multiple properties)', - ) - - results = parser.parse_args([ + results = self.parser.parse_args([ '--property', 'red', '--property', 'green=100%', '--property', 'blue', ]) - failhere = None actual = getattr(results, 'property', {}) - # Verify non-existent red key - try: - failhere = actual['red'] - except Exception as e: - self.assertTrue(type(e) == KeyError) - # Verify removal of blue key - try: - failhere = actual['blue'] - except Exception as e: - self.assertTrue(type(e) == KeyError) # There should be no red or blue - expect = {'green': '100%'} + expect = {'green': '100%', 'format': '#rgb'} self.assertDictEqual(expect, actual) - self.assertEqual(None, failhere) class TestNonNegativeAction(utils.TestCase): - def test_negative_values(self): - parser = argparse.ArgumentParser() + + def setUp(self): + super(TestNonNegativeAction, self).setUp() + + self.parser = argparse.ArgumentParser() # Set up our typical usage - parser.add_argument( + self.parser.add_argument( '--foo', metavar='<foo>', type=int, action=parseractions.NonNegativeAction, ) + def test_negative_values(self): self.assertRaises( argparse.ArgumentTypeError, - parser.parse_args, + self.parser.parse_args, "--foo -1".split() ) def test_zero_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--foo', - metavar='<foo>', - type=int, - action=parseractions.NonNegativeAction, - ) - - results = parser.parse_args( + results = self.parser.parse_args( '--foo 0'.split() ) @@ -141,17 +92,7 @@ class TestNonNegativeAction(utils.TestCase): self.assertEqual(actual, 0) def test_positive_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--foo', - metavar='<foo>', - type=int, - action=parseractions.NonNegativeAction, - ) - - results = parser.parse_args( + results = self.parser.parse_args( '--foo 1'.split() ) diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py index b564ffab..064ad417 100644 --- a/openstackclient/tests/common/test_utils.py +++ b/openstackclient/tests/common/test_utils.py @@ -347,3 +347,10 @@ class TestFindResource(test_utils.TestCase): expected = 'a, b, c' self.assertEqual(expected, utils.format_list(['a', 'b', 'c'])) self.assertEqual(expected, utils.format_list(['c', 'b', 'a'])) + + def test_format_list_separator(self): + expected = 'a\nb\nc' + actual_pre_sorted = utils.format_list(['a', 'b', 'c'], separator='\n') + actual_unsorted = utils.format_list(['c', 'b', 'a'], separator='\n') + self.assertEqual(expected, actual_pre_sorted) + self.assertEqual(expected, actual_unsorted) diff --git a/openstackclient/tests/compute/v2/test_security_group_rule.py b/openstackclient/tests/compute/v2/test_security_group_rule.py index cfe3d46e..0e7ee05d 100644 --- a/openstackclient/tests/compute/v2/test_security_group_rule.py +++ b/openstackclient/tests/compute/v2/test_security_group_rule.py @@ -68,6 +68,28 @@ SECURITY_GROUP = { SECURITY_GROUP_RULE_REMOTE_GROUP], } +security_group_2_id = '12' +security_group_2_name = 'he-shoots' +security_group_2_description = 'he scores' + +SECURITY_GROUP_2_RULE = { + 'id': '2', + 'group': {}, + 'ip_protocol': 'tcp', + 'ip_range': {}, + 'parent_group_id': security_group_2_id, + 'from_port': 80, + 'to_port': 80, +} + +SECURITY_GROUP_2 = { + 'id': security_group_2_id, + 'name': security_group_2_name, + 'description': security_group_2_description, + 'tenant_id': identity_fakes.project_id, + 'rules': [SECURITY_GROUP_2_RULE], +} + class FakeSecurityGroupRuleResource(fakes.FakeResource): @@ -383,12 +405,22 @@ class TestSecurityGroupRuleList(TestSecurityGroupRule): def setUp(self): super(TestSecurityGroupRuleList, self).setUp() - self.secgroups_mock.get.return_value = FakeSecurityGroupRuleResource( + security_group_mock = FakeSecurityGroupRuleResource( None, copy.deepcopy(SECURITY_GROUP), loaded=True, ) + security_group_2_mock = FakeSecurityGroupRuleResource( + None, + copy.deepcopy(SECURITY_GROUP_2), + loaded=True, + ) + + self.secgroups_mock.get.return_value = security_group_mock + self.secgroups_mock.list.return_value = [security_group_mock, + security_group_2_mock] + # Get the command object to test self.cmd = security_group.ListSecurityGroupRule(self.app, None) @@ -420,18 +452,64 @@ class TestSecurityGroupRuleList(TestSecurityGroupRule): security_group_rule_cidr, '0:0', '', - ), ( + ), ( security_group_rule_id, 'icmp', security_group_rule_cidr, '', '', - ), ( + ), ( security_group_rule_id, 'tcp', '', '80:80', 'default', - ), + ),) + self.assertEqual(datalist, tuple(data)) + + def test_security_group_rule_list_no_group(self): + + parsed_args = self.check_parser(self.cmd, [], []) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + collist = ( + 'ID', + 'IP Protocol', + 'IP Range', + 'Port Range', + 'Remote Security Group', + 'Security Group', ) + self.assertEqual(collist, columns) + datalist = (( + security_group_rule_id, + 'tcp', + security_group_rule_cidr, + '0:0', + '', + security_group_id, + ), ( + security_group_rule_id, + 'icmp', + security_group_rule_cidr, + '', + '', + security_group_id, + ), ( + security_group_rule_id, + 'tcp', + '', + '80:80', + 'default', + security_group_id, + ), ( + '2', + 'tcp', + '', + '80:80', + '', + security_group_2_id, + ),) self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index 9f4dcc50..718dff69 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -34,7 +34,15 @@ VERSION = "3" TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, user_name=USERNAME) _s = TEST_RESPONSE_DICT.add_service('identity', name='keystone') -_s.add_endpoint(AUTH_URL + '/v2.0') +_s.add_endpoint(AUTH_URL + ':5000/v2.0') +_s = TEST_RESPONSE_DICT.add_service('network', name='neutron') +_s.add_endpoint(AUTH_URL + ':9696') +_s = TEST_RESPONSE_DICT.add_service('compute', name='nova') +_s.add_endpoint(AUTH_URL + ':8774/v2') +_s = TEST_RESPONSE_DICT.add_service('image', name='glance') +_s.add_endpoint(AUTH_URL + ':9292') +_s = TEST_RESPONSE_DICT.add_service('object', name='swift') +_s.add_endpoint(AUTH_URL + ':8080/v1') TEST_RESPONSE_DICT_V3 = fixture.V3Token(user_name=USERNAME) TEST_RESPONSE_DICT_V3.set_project_scope() @@ -103,6 +111,7 @@ class FakeClientManager(object): self.session = None self.auth_ref = None self.auth_plugin_name = None + self.network_endpoint_enabled = True def get_configuration(self): return { @@ -115,6 +124,9 @@ class FakeClientManager(object): 'identity_api_version': VERSION, } + def is_network_endpoint_enabled(self): + return self.network_endpoint_enabled + class FakeModule(object): def __init__(self, name, version): diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py index 78e5dff7..69b29268 100644 --- a/openstackclient/tests/identity/v2_0/test_project.py +++ b/openstackclient/tests/identity/v2_0/test_project.py @@ -555,12 +555,58 @@ class TestProjectShow(TestProject): identity_fakes.project_id, ) - collist = ('description', 'enabled', 'id', 'name') + collist = ('description', 'enabled', 'id', 'name', 'properties') self.assertEqual(collist, columns) datalist = ( identity_fakes.project_description, True, identity_fakes.project_id, identity_fakes.project_name, + '', ) self.assertEqual(datalist, data) + + +class TestProjectUnset(TestProject): + + def setUp(self): + super(TestProjectUnset, self).setUp() + + project_dict = {'fee': 'fi', 'fo': 'fum'} + project_dict.update(identity_fakes.PROJECT) + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(project_dict), + loaded=True, + ) + + # Get the command object to test + self.cmd = project.UnsetProject(self.app, None) + + def test_project_unset_key(self): + arglist = [ + '--property', 'fee', + '--property', 'fo', + identity_fakes.project_name, + ] + verifylist = [ + ('property', ['fee', 'fo']), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.run(parsed_args) + # Set expected values + kwargs = { + 'description': identity_fakes.project_description, + 'enabled': True, + 'fee': None, + 'fo': None, + 'id': identity_fakes.project_id, + 'name': identity_fakes.project_name, + } + + self.projects_mock.update.assert_called_with( + identity_fakes.project_id, + **kwargs + ) diff --git a/openstackclient/tests/identity/v3/test_project.py b/openstackclient/tests/identity/v3/test_project.py index 0453fd8f..36540201 100644 --- a/openstackclient/tests/identity/v3/test_project.py +++ b/openstackclient/tests/identity/v3/test_project.py @@ -599,7 +599,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { 'name': 'qwerty', - 'domain': identity_fakes.domain_id, } # ProjectManager.update(project, name=, domain=, description=, # enabled=, **kwargs) @@ -628,7 +627,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'description': 'new desc', } self.projects_mock.update.assert_called_with( @@ -655,7 +653,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'enabled': True, } self.projects_mock.update.assert_called_with( @@ -682,7 +679,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'enabled': False, } self.projects_mock.update.assert_called_with( @@ -709,7 +705,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'fee': 'fi', 'fo': 'fum', } diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py index 6dd3a71d..1871ed18 100644 --- a/openstackclient/tests/identity/v3/test_user.py +++ b/openstackclient/tests/identity/v3/test_user.py @@ -1029,6 +1029,25 @@ class TestUserSetPassword(TestUser): current_pass, new_pass ) + def test_user_password_change_no_prompt(self): + current_pass = 'old_pass' + new_pass = 'new_pass' + arglist = [ + '--password', new_pass, + '--original-password', current_pass, + ] + verifylist = [ + ('password', new_pass), + ('original_password', current_pass), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.users_mock.update_password.assert_called_with( + current_pass, new_pass + ) + class TestUserShow(TestUser): diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index 118a119f..02182413 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -57,6 +57,19 @@ class TestImageCreate(TestImage): self.new_image = image_fakes.FakeImage.create_one_image() self.images_mock.create.return_value = self.new_image + + self.project_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + + self.domain_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.DOMAIN), + loaded=True, + ) + # This is the return value for utils.find_resource() self.images_mock.get.return_value = copy.deepcopy( image_fakes.FakeImage.get_image_info(self.new_image)) @@ -123,6 +136,7 @@ class TestImageCreate(TestImage): if self.new_image.protected else '--unprotected'), ('--private' if self.new_image.visibility == 'private' else '--public'), + '--project-domain', identity_fakes.domain_id, self.new_image.name, ] verifylist = [ @@ -135,6 +149,7 @@ class TestImageCreate(TestImage): ('unprotected', not self.new_image.protected), ('public', self.new_image.visibility == 'public'), ('private', self.new_image.visibility == 'private'), + ('project_domain', identity_fakes.domain_id), ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -149,7 +164,7 @@ class TestImageCreate(TestImage): disk_format='fs', min_disk=10, min_ram=4, - owner=self.new_image.owner, + owner=identity_fakes.project_id, protected=self.new_image.protected, visibility=self.new_image.visibility, ) @@ -168,6 +183,40 @@ class TestImageCreate(TestImage): image_fakes.FakeImage.get_image_data(self.new_image), data) + def test_image_create_with_unexist_owner(self): + self.project_mock.get.side_effect = exceptions.NotFound(None) + self.project_mock.find.side_effect = exceptions.NotFound(None) + + arglist = [ + '--container-format', 'ovf', + '--disk-format', 'fs', + '--min-disk', '10', + '--min-ram', '4', + '--owner', 'unexist_owner', + '--protected', + '--private', + image_fakes.image_name, + ] + verifylist = [ + ('container_format', 'ovf'), + ('disk_format', 'fs'), + ('min_disk', 10), + ('min_ram', 4), + ('owner', 'unexist_owner'), + ('protected', True), + ('unprotected', False), + ('public', False), + ('private', True), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args, + ) + @mock.patch('glanceclient.common.utils.get_data_file', name='Open') def test_image_create_file(self, mock_open): mock_file = mock.MagicMock(name='File') @@ -686,6 +735,18 @@ class TestImageSet(TestImage): schemas.SchemaBasedModel, ) + self.project_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + + self.domain_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.DOMAIN), + loaded=True, + ) + self.images_mock.get.return_value = self.model(**image_fakes.IMAGE) self.images_mock.update.return_value = self.model(**image_fakes.IMAGE) # Get the command object to test @@ -694,20 +755,22 @@ class TestImageSet(TestImage): def test_image_set_options(self): arglist = [ '--name', 'new-name', - '--owner', 'new-owner', + '--owner', identity_fakes.project_name, '--min-disk', '2', '--min-ram', '4', '--container-format', 'ovf', '--disk-format', 'vmdk', + '--project-domain', identity_fakes.domain_id, image_fakes.image_id, ] verifylist = [ ('name', 'new-name'), - ('owner', 'new-owner'), + ('owner', identity_fakes.project_name), ('min_disk', 2), ('min_ram', 4), ('container_format', 'ovf'), ('disk_format', 'vmdk'), + ('project_domain', identity_fakes.domain_id), ('image', image_fakes.image_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -717,7 +780,7 @@ class TestImageSet(TestImage): kwargs = { 'name': 'new-name', - 'owner': 'new-owner', + 'owner': identity_fakes.project_id, 'min_disk': 2, 'min_ram': 4, 'container_format': 'ovf', @@ -727,6 +790,25 @@ class TestImageSet(TestImage): self.images_mock.update.assert_called_with( image_fakes.image_id, **kwargs) + def test_image_set_with_unexist_owner(self): + self.project_mock.get.side_effect = exceptions.NotFound(None) + self.project_mock.find.side_effect = exceptions.NotFound(None) + + arglist = [ + '--owner', 'unexist_owner', + image_fakes.image_id, + ] + verifylist = [ + ('owner', 'unexist_owner'), + ('image', image_fakes.image_id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, parsed_args) + def test_image_set_bools1(self): arglist = [ '--protected', diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py index b45c5412..80760a77 100644 --- a/openstackclient/tests/network/v2/fakes.py +++ b/openstackclient/tests/network/v2/fakes.py @@ -73,11 +73,12 @@ class FakeNetwork(object): router_external, status, subnets, tenant_id """ # Set default attributes. + project_id = 'project-id-' + uuid.uuid4().hex network_attrs = { 'id': 'network-id-' + uuid.uuid4().hex, 'name': 'network-name-' + uuid.uuid4().hex, 'status': 'ACTIVE', - 'tenant_id': 'project-id-' + uuid.uuid4().hex, + 'tenant_id': project_id, 'admin_state_up': True, 'shared': False, 'subnets': ['a', 'b'], @@ -101,6 +102,8 @@ class FakeNetwork(object): network = fakes.FakeResource(info=copy.deepcopy(network_attrs), methods=copy.deepcopy(network_methods), loaded=True) + network.project_id = project_id + return network @staticmethod diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py index f22224b6..12ac802c 100644 --- a/openstackclient/tests/network/v2/test_network.py +++ b/openstackclient/tests/network/v2/test_network.py @@ -44,20 +44,20 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'admin_state_up', 'id', 'name', + 'project_id', 'router_external', 'status', 'subnets', - 'tenant_id', ) data = ( network._format_admin_state(_network.admin_state_up), _network.id, _network.name, + _network.project_id, network._format_router_external(_network.router_external), _network.status, utils.format_list(_network.subnets), - _network.tenant_id, ) def setUp(self): @@ -186,20 +186,20 @@ class TestCreateNetworkIdentityV2(TestNetwork): 'admin_state_up', 'id', 'name', + 'project_id', 'router_external', 'status', 'subnets', - 'tenant_id', ) data = ( network._format_admin_state(_network.admin_state_up), _network.id, _network.name, + _network.project_id, network._format_router_external(_network.router_external), _network.status, utils.format_list(_network.subnets), - _network.tenant_id, ) def setUp(self): @@ -340,7 +340,7 @@ class TestListNetwork(TestNetwork): net.id, net.name, net.status, - net.tenant_id, + net.project_id, network._format_admin_state(net.admin_state_up), net.shared, utils.format_list(net.subnets), @@ -485,20 +485,20 @@ class TestShowNetwork(TestNetwork): 'admin_state_up', 'id', 'name', + 'project_id', 'router_external', 'status', 'subnets', - 'tenant_id', ) data = ( network._format_admin_state(_network.admin_state_up), _network.id, _network.name, + _network.project_id, network._format_router_external(_network.router_external), _network.status, utils.format_list(_network.subnets), - _network.tenant_id, ) def setUp(self): diff --git a/openstackclient/tests/test_shell.py b/openstackclient/tests/test_shell.py index c548d890..c4546d89 100644 --- a/openstackclient/tests/test_shell.py +++ b/openstackclient/tests/test_shell.py @@ -76,7 +76,7 @@ CLOUD_2 = { 'project_name': 'heart-o-gold', 'username': 'zaphod', }, - 'region_name': 'occ-cloud', + 'region_name': 'occ-cloud,krikkit,occ-env', 'log_file': '/tmp/test_log_file', 'log_level': 'debug', } diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py index c668e366..4f2ff8bb 100644 --- a/openstackclient/volume/v1/backup.py +++ b/openstackclient/volume/v1/backup.py @@ -95,7 +95,6 @@ class DeleteBackup(command.Command): backup_id = utils.find_resource(volume_client.backups, backup).id volume_client.backups.delete(backup_id) - return class ListBackup(lister.Lister): diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py index d1c70113..73e70a21 100644 --- a/openstackclient/volume/v1/qos_specs.py +++ b/openstackclient/volume/v1/qos_specs.py @@ -55,8 +55,6 @@ class AssociateQos(command.Command): volume_client.qos_specs.associate(qos_spec.id, volume_type.id) - return - class CreateQos(show.ShowOne): """Create new QoS specification""" @@ -123,7 +121,6 @@ class DeleteQos(command.Command): 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 class DisassociateQos(command.Command): @@ -166,8 +163,6 @@ class DisassociateQos(command.Command): elif parsed_args.all: volume_client.qos_specs.disassociate_all(qos_spec.id) - return - class ListQos(lister.Lister): """List QoS specifications""" @@ -230,8 +225,6 @@ class SetQos(command.Command): else: self.app.log.error("No changes requested\n") - return - class ShowQos(show.ShowOne): """Display QoS specification details""" @@ -298,5 +291,3 @@ class UnsetQos(command.Command): parsed_args.property) else: self.app.log.error("No changes requested\n") - - return diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index 93e17eb8..24379a9a 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -100,7 +100,6 @@ class DeleteSnapshot(command.Command): snapshot_id = utils.find_resource(volume_client.volume_snapshots, snapshot).id volume_client.volume_snapshots.delete(snapshot_id) - return class ListSnapshot(lister.Lister): @@ -226,7 +225,6 @@ class SetSnapshot(command.Command): return snapshot.update(**kwargs) - return class ShowSnapshot(show.ShowOne): @@ -291,4 +289,3 @@ class UnsetSnapshot(command.Command): ) else: self.app.log.error("No changes requested\n") - return diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index 0691d884..17b6c9c8 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -196,7 +196,6 @@ class DeleteVolume(command.Command): volume_client.volumes.force_delete(volume_obj.id) else: volume_client.volumes.delete(volume_obj.id) - return class ListVolume(lister.Lister): @@ -382,8 +381,6 @@ class SetVolume(command.Command): if not kwargs and not parsed_args.property and not parsed_args.size: self.app.log.error("No changes requested\n") - return - class ShowVolume(show.ShowOne): """Show volume details""" @@ -454,4 +451,3 @@ class UnsetVolume(command.Command): ) else: self.app.log.error("No changes requested\n") - return diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py index d7765c79..b664adfb 100644 --- a/openstackclient/volume/v1/volume_type.py +++ b/openstackclient/volume/v1/volume_type.py @@ -81,7 +81,6 @@ class DeleteVolumeType(command.Command): volume_type_id = utils.find_resource( volume_client.volume_types, parsed_args.volume_type).id volume_client.volume_types.delete(volume_type_id) - return class ListVolumeType(lister.Lister): @@ -144,8 +143,6 @@ class SetVolumeType(command.Command): if parsed_args.property: volume_type.set_keys(parsed_args.property) - return - class UnsetVolumeType(command.Command): """Unset volume type properties""" @@ -182,7 +179,6 @@ class UnsetVolumeType(command.Command): volume_type.unset_keys(parsed_args.property) else: self.app.log.error("No changes requested\n") - return class ShowVolumeType(show.ShowOne): diff --git a/openstackclient/volume/v2/backup.py b/openstackclient/volume/v2/backup.py index 3525e701..bc919d0b 100644 --- a/openstackclient/volume/v2/backup.py +++ b/openstackclient/volume/v2/backup.py @@ -92,7 +92,6 @@ class DeleteBackup(command.Command): backup_id = utils.find_resource( volume_client.backups, backup).id volume_client.backups.delete(backup_id) - return class ListBackup(lister.Lister): diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index b3a34cac..678fde4f 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -55,8 +55,6 @@ class AssociateQos(command.Command): volume_client.qos_specs.associate(qos_spec.id, volume_type.id) - return - class CreateQos(show.ShowOne): """Create new QoS specification""" @@ -123,7 +121,6 @@ class DeleteQos(command.Command): 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 class DisassociateQos(command.Command): @@ -166,8 +163,6 @@ class DisassociateQos(command.Command): elif parsed_args.all: volume_client.qos_specs.disassociate_all(qos_spec.id) - return - class ListQos(lister.Lister): """List QoS specifications""" @@ -230,8 +225,6 @@ class SetQos(command.Command): else: self.app.log.error("No changes requested\n") - return - class ShowQos(show.ShowOne): """Display QoS specification details""" @@ -298,5 +291,3 @@ class UnsetQos(command.Command): parsed_args.property) else: self.app.log.error("No changes requested\n") - - return diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py index aa7630ae..f939a553 100644 --- a/openstackclient/volume/v2/snapshot.py +++ b/openstackclient/volume/v2/snapshot.py @@ -97,7 +97,6 @@ class DeleteSnapshot(command.Command): snapshot_id = utils.find_resource( volume_client.volume_snapshots, snapshot).id volume_client.volume_snapshots.delete(snapshot_id) - return class ListSnapshot(lister.Lister): @@ -217,7 +216,6 @@ class SetSnapshot(command.Command): volume_client.volume_snapshots.set_metadata(snapshot.id, parsed_args.property) volume_client.volume_snapshots.update(snapshot.id, **kwargs) - return class ShowSnapshot(show.ShowOne): @@ -280,4 +278,3 @@ class UnsetSnapshot(command.Command): ) else: self.app.log.error("No changes requested\n") - return diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index bbcceca6..c636cf2f 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -189,7 +189,6 @@ class DeleteVolume(command.Command): volume_client.volumes.force_delete(volume_obj.id) else: volume_client.volumes.delete(volume_obj.id) - return class ListVolume(lister.Lister): @@ -394,8 +393,6 @@ class SetVolume(command.Command): if not kwargs and not parsed_args.property and not parsed_args.size: self.app.log.error("No changes requested\n") - return - class ShowVolume(show.ShowOne): """Display volume details""" @@ -452,4 +449,3 @@ class UnsetVolume(command.Command): volume_client.volumes.delete_metadata( volume.id, parsed_args.property) - return diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 583e6ed9..06ab8f82 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -110,7 +110,6 @@ class DeleteVolumeType(command.Command): volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) volume_client.volume_types.delete(volume_type.id) - return class ListVolumeType(lister.Lister): @@ -201,8 +200,6 @@ class SetVolumeType(command.Command): if parsed_args.property: volume_type.set_keys(parsed_args.property) - return - class ShowVolumeType(show.ShowOne): """Display volume type details""" @@ -258,4 +255,3 @@ class UnsetVolumeType(command.Command): parsed_args.volume_type, ) volume_type.unset_keys(parsed_args.property) - return |
