summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/common/clientmanager.py20
-rw-r--r--openstackclient/common/commandmanager.py4
-rw-r--r--openstackclient/common/extension.py4
-rw-r--r--openstackclient/common/limits.py2
-rw-r--r--openstackclient/common/utils.py11
-rw-r--r--openstackclient/compute/v2/security_group.py54
-rw-r--r--openstackclient/compute/v2/server.py10
-rw-r--r--openstackclient/compute/v2/service.py2
-rw-r--r--openstackclient/identity/v2_0/project.py56
-rw-r--r--openstackclient/identity/v3/project.py8
-rw-r--r--openstackclient/identity/v3/user.py31
-rw-r--r--openstackclient/image/v1/image.py2
-rw-r--r--openstackclient/image/v2/image.py18
-rw-r--r--openstackclient/network/v2/network.py19
-rw-r--r--openstackclient/object/client.py4
-rw-r--r--openstackclient/tests/common/test_clientmanager.py33
-rw-r--r--openstackclient/tests/common/test_logs.py6
-rw-r--r--openstackclient/tests/common/test_parseractions.py97
-rw-r--r--openstackclient/tests/common/test_utils.py7
-rw-r--r--openstackclient/tests/compute/v2/test_security_group_rule.py86
-rw-r--r--openstackclient/tests/fakes.py14
-rw-r--r--openstackclient/tests/identity/v2_0/test_project.py48
-rw-r--r--openstackclient/tests/identity/v3/test_project.py5
-rw-r--r--openstackclient/tests/identity/v3/test_user.py19
-rw-r--r--openstackclient/tests/image/v2/test_image.py90
-rw-r--r--openstackclient/tests/network/v2/fakes.py5
-rw-r--r--openstackclient/tests/network/v2/test_network.py14
-rw-r--r--openstackclient/tests/test_shell.py2
-rw-r--r--openstackclient/volume/v1/backup.py1
-rw-r--r--openstackclient/volume/v1/qos_specs.py9
-rw-r--r--openstackclient/volume/v1/snapshot.py3
-rw-r--r--openstackclient/volume/v1/volume.py4
-rw-r--r--openstackclient/volume/v1/volume_type.py4
-rw-r--r--openstackclient/volume/v2/backup.py1
-rw-r--r--openstackclient/volume/v2/qos_specs.py9
-rw-r--r--openstackclient/volume/v2/snapshot.py3
-rw-r--r--openstackclient/volume/v2/volume.py4
-rw-r--r--openstackclient/volume/v2/volume_type.py4
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