summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/api/auth.py230
-rw-r--r--openstackclient/api/auth_plugin.py4
-rwxr-xr-x[-rw-r--r--]openstackclient/common/availability_zone.py4
-rw-r--r--openstackclient/common/clientmanager.py78
-rwxr-xr-x[-rw-r--r--]openstackclient/common/quota.py2
-rw-r--r--openstackclient/compute/v2/agent.py36
-rw-r--r--openstackclient/compute/v2/console.py2
-rw-r--r--openstackclient/compute/v2/fixedip.py34
-rw-r--r--openstackclient/compute/v2/flavor.py21
-rw-r--r--openstackclient/compute/v2/floatingip.py34
-rw-r--r--openstackclient/compute/v2/floatingippool.py36
-rw-r--r--openstackclient/compute/v2/keypair.py2
-rw-r--r--openstackclient/compute/v2/server.py114
-rw-r--r--openstackclient/identity/client.py2
-rw-r--r--openstackclient/identity/v2_0/ec2creds.py4
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v2_0/project.py8
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v2_0/role.py4
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v2_0/user.py8
-rw-r--r--openstackclient/identity/v3/consumer.py35
-rw-r--r--openstackclient/identity/v3/credential.py47
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v3/domain.py33
-rw-r--r--openstackclient/identity/v3/ec2creds.py25
-rw-r--r--openstackclient/identity/v3/endpoint.py37
-rw-r--r--openstackclient/identity/v3/federation_protocol.py28
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v3/group.py7
-rw-r--r--openstackclient/identity/v3/identity_provider.py31
-rw-r--r--openstackclient/identity/v3/mapping.py26
-rw-r--r--openstackclient/identity/v3/policy.py30
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v3/project.py11
-rw-r--r--openstackclient/identity/v3/region.py30
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v3/role.py8
-rw-r--r--openstackclient/identity/v3/service.py39
-rw-r--r--openstackclient/identity/v3/service_provider.py35
-rwxr-xr-x[-rw-r--r--]openstackclient/identity/v3/user.py17
-rw-r--r--openstackclient/image/v1/image.py2
-rwxr-xr-x[-rw-r--r--]openstackclient/image/v2/image.py10
-rw-r--r--openstackclient/network/common.py2
-rw-r--r--openstackclient/network/v2/floating_ip_pool.py66
-rw-r--r--openstackclient/network/v2/port.py73
-rw-r--r--openstackclient/network/v2/subnet.py86
-rw-r--r--openstackclient/network/v2/subnet_pool.py41
-rwxr-xr-x[-rw-r--r--]openstackclient/shell.py4
-rw-r--r--openstackclient/tests/common/test_clientmanager.py4
-rw-r--r--openstackclient/tests/compute/v2/fakes.py75
-rw-r--r--openstackclient/tests/compute/v2/test_agent.py73
-rw-r--r--openstackclient/tests/compute/v2/test_flavor.py20
-rw-r--r--openstackclient/tests/compute/v2/test_server.py195
-rw-r--r--openstackclient/tests/compute/v2/test_server_backup.py4
-rw-r--r--openstackclient/tests/compute/v2/test_server_image.py4
-rw-r--r--openstackclient/tests/identity/v3/fakes.py64
-rw-r--r--openstackclient/tests/identity/v3/test_consumer.py2
-rw-r--r--openstackclient/tests/identity/v3/test_domain.py142
-rw-r--r--openstackclient/tests/identity/v3/test_endpoint.py14
-rw-r--r--openstackclient/tests/identity/v3/test_identity_provider.py10
-rw-r--r--openstackclient/tests/identity/v3/test_mappings.py2
-rw-r--r--openstackclient/tests/identity/v3/test_project.py451
-rw-r--r--openstackclient/tests/identity/v3/test_protocol.py2
-rw-r--r--openstackclient/tests/identity/v3/test_region.py8
-rw-r--r--openstackclient/tests/identity/v3/test_service.py2
-rw-r--r--openstackclient/tests/identity/v3/test_service_provider.py16
-rw-r--r--openstackclient/tests/image/v1/test_image.py2
-rw-r--r--openstackclient/tests/image/v2/fakes.py35
-rw-r--r--openstackclient/tests/image/v2/test_image.py14
-rw-r--r--openstackclient/tests/network/v2/test_address_scope.py27
-rw-r--r--openstackclient/tests/network/v2/test_floating_ip.py4
-rw-r--r--openstackclient/tests/network/v2/test_floating_ip_pool.py97
-rw-r--r--openstackclient/tests/network/v2/test_ip_availability.py14
-rw-r--r--openstackclient/tests/network/v2/test_network.py50
-rw-r--r--openstackclient/tests/network/v2/test_port.py119
-rw-r--r--openstackclient/tests/network/v2/test_security_group.py35
-rw-r--r--openstackclient/tests/network/v2/test_security_group_rule.py34
-rw-r--r--openstackclient/tests/network/v2/test_subnet.py129
-rw-r--r--openstackclient/tests/network/v2/test_subnet_pool.py64
-rw-r--r--openstackclient/tests/volume/test_find_resource.py8
-rw-r--r--openstackclient/tests/volume/v1/fakes.py4
-rw-r--r--openstackclient/tests/volume/v2/fakes.py87
-rw-r--r--openstackclient/tests/volume/v2/test_backup.py98
-rw-r--r--openstackclient/tests/volume/v2/test_qos_specs.py72
-rw-r--r--openstackclient/tests/volume/v2/test_snapshot.py72
-rw-r--r--openstackclient/tests/volume/v2/test_type.py20
-rw-r--r--openstackclient/tests/volume/v2/test_volume.py33
-rw-r--r--openstackclient/volume/v1/volume.py1
-rw-r--r--openstackclient/volume/v2/backup.py50
-rw-r--r--openstackclient/volume/v2/qos_specs.py26
-rw-r--r--openstackclient/volume/v2/snapshot.py38
-rw-r--r--openstackclient/volume/v2/volume.py30
-rw-r--r--openstackclient/volume/v2/volume_type.py29
87 files changed, 2603 insertions, 1023 deletions
diff --git a/openstackclient/api/auth.py b/openstackclient/api/auth.py
index 0c82fe9b..d62a82dc 100644
--- a/openstackclient/api/auth.py
+++ b/openstackclient/api/auth.py
@@ -11,229 +11,15 @@
# under the License.
#
-"""Authentication Library"""
+# NOTE(dtroyer): This file is deprecated in Jun 2016, remove after 4.x release
+# or Jun 2017.
-import argparse
-import logging
+import sys
-from keystoneauth1.loading import base
-from osc_lib import exceptions as exc
-from osc_lib import utils
+from osc_lib.api.auth import * # noqa
-from openstackclient.i18n import _
-LOG = logging.getLogger(__name__)
-
-# Initialize the list of Authentication plugins early in order
-# to get the command-line options
-PLUGIN_LIST = None
-
-# List of plugin command line options
-OPTIONS_LIST = {}
-
-
-def get_plugin_list():
- """Gather plugin list and cache it"""
- global PLUGIN_LIST
-
- if PLUGIN_LIST is None:
- PLUGIN_LIST = base.get_available_plugin_names()
- return PLUGIN_LIST
-
-
-def get_options_list():
- """Gather plugin options so the help action has them available"""
-
- global OPTIONS_LIST
-
- if not OPTIONS_LIST:
- for plugin_name in get_plugin_list():
- plugin_options = base.get_plugin_options(plugin_name)
- for o in plugin_options:
- os_name = o.dest.lower().replace('_', '-')
- os_env_name = 'OS_' + os_name.upper().replace('-', '_')
- OPTIONS_LIST.setdefault(
- os_name, {'env': os_env_name, 'help': ''},
- )
- # TODO(mhu) simplistic approach, would be better to only add
- # help texts if they vary from one auth plugin to another
- # also the text rendering is ugly in the CLI ...
- OPTIONS_LIST[os_name]['help'] += 'With %s: %s\n' % (
- plugin_name,
- o.help,
- )
- return OPTIONS_LIST
-
-
-def select_auth_plugin(options):
- """Pick an auth plugin based on --os-auth-type or other options"""
-
- auth_plugin_name = None
-
- # Do the token/url check first as this must override the default
- # 'password' set by os-client-config
- # Also, url and token are not copied into o-c-c's auth dict (yet?)
- if options.auth.get('url') and options.auth.get('token'):
- # service token authentication
- auth_plugin_name = 'token_endpoint'
- elif options.auth_type in PLUGIN_LIST:
- # A direct plugin name was given, use it
- auth_plugin_name = options.auth_type
- elif options.auth.get('username'):
- if options.identity_api_version == '3':
- auth_plugin_name = 'v3password'
- elif options.identity_api_version.startswith('2'):
- auth_plugin_name = 'v2password'
- else:
- # let keystoneclient figure it out itself
- auth_plugin_name = 'password'
- elif options.auth.get('token'):
- if options.identity_api_version == '3':
- auth_plugin_name = 'v3token'
- elif options.identity_api_version.startswith('2'):
- auth_plugin_name = 'v2token'
- else:
- # let keystoneclient figure it out itself
- auth_plugin_name = 'token'
- else:
- # The ultimate default is similar to the original behaviour,
- # but this time with version discovery
- auth_plugin_name = 'password'
- LOG.debug("Auth plugin %s selected", auth_plugin_name)
- return auth_plugin_name
-
-
-def build_auth_params(auth_plugin_name, cmd_options):
-
- if auth_plugin_name:
- LOG.debug('auth_type: %s', auth_plugin_name)
- auth_plugin_loader = base.get_plugin_loader(auth_plugin_name)
- auth_params = {opt.dest: opt.default
- for opt in base.get_plugin_options(auth_plugin_name)}
- auth_params.update(dict(cmd_options.auth))
- # grab tenant from project for v2.0 API compatibility
- if auth_plugin_name.startswith("v2"):
- if 'project_id' in auth_params:
- auth_params['tenant_id'] = auth_params['project_id']
- del auth_params['project_id']
- if 'project_name' in auth_params:
- auth_params['tenant_name'] = auth_params['project_name']
- del auth_params['project_name']
- else:
- LOG.debug('no auth_type')
- # delay the plugin choice, grab every option
- auth_plugin_loader = None
- auth_params = dict(cmd_options.auth)
- plugin_options = set([o.replace('-', '_') for o in get_options_list()])
- for option in plugin_options:
- LOG.debug('fetching option %s', option)
- auth_params[option] = getattr(cmd_options.auth, option, None)
- return (auth_plugin_loader, auth_params)
-
-
-def check_valid_authorization_options(options, auth_plugin_name):
- """Validate authorization options, and provide helpful error messages."""
- if (options.auth.get('project_id') and not
- options.auth.get('domain_id') and not
- options.auth.get('domain_name') and not
- options.auth.get('project_name') and not
- options.auth.get('tenant_id') and not
- options.auth.get('tenant_name')):
- raise exc.CommandError(_(
- 'Missing parameter(s): '
- 'Set either a project or a domain scope, but not both. Set a '
- 'project scope with --os-project-name, OS_PROJECT_NAME, or '
- 'auth.project_name. Alternatively, set a domain scope with '
- '--os-domain-name, OS_DOMAIN_NAME or auth.domain_name.'))
-
-
-def check_valid_authentication_options(options, auth_plugin_name):
- """Validate authentication options, and provide helpful error messages."""
-
- # Get all the options defined within the plugin.
- plugin_opts = base.get_plugin_options(auth_plugin_name)
- plugin_opts = {opt.dest: opt for opt in plugin_opts}
-
- # NOTE(aloga): this is an horrible hack. We need a way to specify the
- # required options in the plugins. Using the "required" argument for
- # the oslo_config.cfg.Opt does not work, as it is not possible to load the
- # plugin if the option is not defined, so the error will simply be:
- # "NoMatchingPlugin: The plugin foobar could not be found"
- msgs = []
- if 'password' in plugin_opts and not options.auth.get('username'):
- msgs.append(_('Set a username with --os-username, OS_USERNAME,'
- ' or auth.username'))
- if 'auth_url' in plugin_opts and not options.auth.get('auth_url'):
- msgs.append(_('Set a service AUTH_URL, with --os-auth-url, '
- 'OS_AUTH_URL or auth.auth_url'))
- if 'url' in plugin_opts and not options.auth.get('url'):
- msgs.append(_('Set a service URL, with --os-url, '
- 'OS_URL or auth.url'))
- if 'token' in plugin_opts and not options.auth.get('token'):
- msgs.append(_('Set a token with --os-token, '
- 'OS_TOKEN or auth.token'))
- if msgs:
- raise exc.CommandError(
- _('Missing parameter(s): \n%s') % '\n'.join(msgs))
-
-
-def build_auth_plugins_option_parser(parser):
- """Auth plugins options builder
-
- Builds dynamically the list of options expected by each available
- authentication plugin.
-
- """
- available_plugins = list(get_plugin_list())
- parser.add_argument(
- '--os-auth-type',
- metavar='<auth-type>',
- dest='auth_type',
- default=utils.env('OS_AUTH_TYPE'),
- help=_('Select an authentication type. Available types: %s.'
- ' Default: selected based on --os-username/--os-token'
- ' (Env: OS_AUTH_TYPE)') % ', '.join(available_plugins),
- choices=available_plugins
- )
- # Maintain compatibility with old tenant env vars
- envs = {
- 'OS_PROJECT_NAME': utils.env(
- 'OS_PROJECT_NAME',
- default=utils.env('OS_TENANT_NAME')
- ),
- 'OS_PROJECT_ID': utils.env(
- 'OS_PROJECT_ID',
- default=utils.env('OS_TENANT_ID')
- ),
- }
- for o in get_options_list():
- # Remove tenant options from KSC plugins and replace them below
- if 'tenant' not in o:
- parser.add_argument(
- '--os-' + o,
- metavar='<auth-%s>' % o,
- dest=o.replace('-', '_'),
- default=envs.get(
- OPTIONS_LIST[o]['env'],
- utils.env(OPTIONS_LIST[o]['env']),
- ),
- help=_('%(help)s\n(Env: %(env)s)') % {
- 'help': OPTIONS_LIST[o]['help'],
- 'env': OPTIONS_LIST[o]['env'],
- },
- )
- # add tenant-related options for compatibility
- # this is deprecated but still used in some tempest tests...
- parser.add_argument(
- '--os-tenant-name',
- metavar='<auth-tenant-name>',
- dest='os_project_name',
- help=argparse.SUPPRESS,
- )
- parser.add_argument(
- '--os-tenant-id',
- metavar='<auth-tenant-id>',
- dest='os_project_id',
- help=argparse.SUPPRESS,
- )
- return parser
+sys.stderr.write(
+ "WARNING: %s is deprecated and will be removed after Jun 2017. "
+ "Please use osc_lib.api.auth\n" % __name__
+)
diff --git a/openstackclient/api/auth_plugin.py b/openstackclient/api/auth_plugin.py
index dc47a688..a106b1eb 100644
--- a/openstackclient/api/auth_plugin.py
+++ b/openstackclient/api/auth_plugin.py
@@ -13,15 +13,11 @@
"""Authentication Plugin Library"""
-import logging
-
from keystoneauth1 import loading
from keystoneauth1 import token_endpoint
from openstackclient.i18n import _
-LOG = logging.getLogger(__name__)
-
class TokenEndpoint(loading.BaseLoader):
"""Auth plugin to handle traditional token/endpoint usage
diff --git a/openstackclient/common/availability_zone.py b/openstackclient/common/availability_zone.py
index 89d77d15..63c55370 100644..100755
--- a/openstackclient/common/availability_zone.py
+++ b/openstackclient/common/availability_zone.py
@@ -122,11 +122,11 @@ class ListAvailabilityZone(command.Lister):
compute_client = self.app.client_manager.compute
try:
data = compute_client.availability_zones.list()
- except nova_exceptions.Forbidden as e: # policy doesn't allow
+ except nova_exceptions.Forbidden: # policy doesn't allow
try:
data = compute_client.availability_zones.list(detailed=False)
except Exception:
- raise e
+ raise
# Argh, the availability zones are not iterable...
result = []
diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py
index 3c35b529..ec005dc0 100644
--- a/openstackclient/common/clientmanager.py
+++ b/openstackclient/common/clientmanager.py
@@ -20,12 +20,13 @@ import logging
import pkg_resources
import sys
+from keystoneauth1.loading import base
+from osc_lib.api import auth
from osc_lib import exceptions
from oslo_utils import strutils
import requests
import six
-from openstackclient.api import auth
from openstackclient.common import session as osc_session
from openstackclient.identity import client as identity_client
@@ -37,6 +38,77 @@ PLUGIN_MODULES = []
USER_AGENT = 'python-openstackclient'
+# NOTE(dtroyer): Bringing back select_auth_plugin() and build_auth_params()
+# temporarily because osc-lib 0.3.0 removed it a wee bit early
+def select_auth_plugin(options):
+ """Pick an auth plugin based on --os-auth-type or other options"""
+
+ auth_plugin_name = None
+
+ # Do the token/url check first as this must override the default
+ # 'password' set by os-client-config
+ # Also, url and token are not copied into o-c-c's auth dict (yet?)
+ if options.auth.get('url') and options.auth.get('token'):
+ # service token authentication
+ auth_plugin_name = 'token_endpoint'
+ elif options.auth_type in auth.PLUGIN_LIST:
+ # A direct plugin name was given, use it
+ auth_plugin_name = options.auth_type
+ elif options.auth.get('username'):
+ if options.identity_api_version == '3':
+ auth_plugin_name = 'v3password'
+ elif options.identity_api_version.startswith('2'):
+ auth_plugin_name = 'v2password'
+ else:
+ # let keystoneauth figure it out itself
+ auth_plugin_name = 'password'
+ elif options.auth.get('token'):
+ if options.identity_api_version == '3':
+ auth_plugin_name = 'v3token'
+ elif options.identity_api_version.startswith('2'):
+ auth_plugin_name = 'v2token'
+ else:
+ # let keystoneauth figure it out itself
+ auth_plugin_name = 'token'
+ else:
+ # The ultimate default is similar to the original behaviour,
+ # but this time with version discovery
+ auth_plugin_name = 'password'
+ LOG.debug("Auth plugin %s selected", auth_plugin_name)
+ return auth_plugin_name
+
+
+def build_auth_params(auth_plugin_name, cmd_options):
+ if auth_plugin_name:
+ LOG.debug('auth_type: %s', auth_plugin_name)
+ auth_plugin_loader = base.get_plugin_loader(auth_plugin_name)
+ auth_params = {
+ opt.dest: opt.default
+ for opt in base.get_plugin_options(auth_plugin_name)
+ }
+ auth_params.update(dict(cmd_options.auth))
+ # grab tenant from project for v2.0 API compatibility
+ if auth_plugin_name.startswith("v2"):
+ if 'project_id' in auth_params:
+ auth_params['tenant_id'] = auth_params['project_id']
+ del auth_params['project_id']
+ if 'project_name' in auth_params:
+ auth_params['tenant_name'] = auth_params['project_name']
+ del auth_params['project_name']
+ else:
+ LOG.debug('no auth_type')
+ # delay the plugin choice, grab every option
+ auth_plugin_loader = None
+ auth_params = dict(cmd_options.auth)
+ plugin_options = set(
+ [o.replace('-', '_') for o in auth.get_options_list()]
+ )
+ for option in plugin_options:
+ LOG.debug('fetching option %s', option)
+ auth_params[option] = getattr(cmd_options.auth, option, None)
+ return (auth_plugin_loader, auth_params)
+
+
class ClientCache(object):
"""Descriptor class for caching created client handles."""
@@ -193,7 +265,7 @@ class ClientManager(object):
# If no auth type is named by the user, select one based on
# the supplied options
- self.auth_plugin_name = auth.select_auth_plugin(self._cli_options)
+ self.auth_plugin_name = select_auth_plugin(self._cli_options)
# Basic option checking to avoid unhelpful error messages
auth.check_valid_authentication_options(self._cli_options,
@@ -205,7 +277,7 @@ class ClientManager(object):
not self._cli_options.auth.get('password')):
self._cli_options.auth['password'] = self._pw_callback()
- (auth_plugin, self._auth_params) = auth.build_auth_params(
+ (auth_plugin, self._auth_params) = build_auth_params(
self.auth_plugin_name,
self._cli_options,
)
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py
index 69415f0d..3c12c366 100644..100755
--- a/openstackclient/common/quota.py
+++ b/openstackclient/common/quota.py
@@ -231,7 +231,7 @@ class ShowQuota(command.ShowOne):
if type(e).__name__ == 'EndpointNotFound':
return {}
else:
- raise e
+ raise
return quota._info
def get_network_quota(self, parsed_args):
diff --git a/openstackclient/compute/v2/agent.py b/openstackclient/compute/v2/agent.py
index 4d923955..76c1b3b7 100644
--- a/openstackclient/compute/v2/agent.py
+++ b/openstackclient/compute/v2/agent.py
@@ -152,28 +152,48 @@ class SetAgent(command.Command):
help=_("ID of the agent")
)
parser.add_argument(
- "version",
+ "--agent-version",
+ dest="version",
metavar="<version>",
help=_("Version of the agent")
)
parser.add_argument(
- "url",
+ "--url",
metavar="<url>",
- help=_("URL")
+ help=_("URL of the agent")
)
parser.add_argument(
- "md5hash",
+ "--md5hash",
metavar="<md5hash>",
- help=_("MD5 hash")
+ help=_("MD5 hash of the agent")
)
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
+ data = compute_client.agents.list(hypervisor=None)
+ agent = {}
+
+ for s in data:
+ if s.agent_id == int(parsed_args.id):
+ agent['version'] = s.version
+ agent['url'] = s.url
+ agent['md5hash'] = s.md5hash
+ if agent == {}:
+ msg = _("No agent with a ID of '%(id)s' exists.")
+ raise exceptions.CommandError(msg % parsed_args.id)
+
+ if parsed_args.version:
+ agent['version'] = parsed_args.version
+ if parsed_args.url:
+ agent['url'] = parsed_args.url
+ if parsed_args.md5hash:
+ agent['md5hash'] = parsed_args.md5hash
+
args = (
parsed_args.id,
- parsed_args.version,
- parsed_args.url,
- parsed_args.md5hash
+ agent['version'],
+ agent['url'],
+ agent['md5hash'],
)
compute_client.agents.update(*args)
diff --git a/openstackclient/compute/v2/console.py b/openstackclient/compute/v2/console.py
index 4179fa5c..74bed441 100644
--- a/openstackclient/compute/v2/console.py
+++ b/openstackclient/compute/v2/console.py
@@ -87,7 +87,7 @@ class ShowConsoleURL(command.ShowOne):
dest='url_type',
action='store_const',
const='xvpvnc',
- help=_("Show xpvnc console URL")
+ help=_("Show xvpvnc console URL")
)
type_group.add_argument(
'--spice',
diff --git a/openstackclient/compute/v2/fixedip.py b/openstackclient/compute/v2/fixedip.py
index 8bd72ca3..c14d29fa 100644
--- a/openstackclient/compute/v2/fixedip.py
+++ b/openstackclient/compute/v2/fixedip.py
@@ -15,28 +15,43 @@
"""Fixed IP action implementations"""
+import logging
+
from osc_lib.command import command
from osc_lib import utils
+from openstackclient.i18n import _
+
class AddFixedIP(command.Command):
"""Add fixed IP address to server"""
+ # TODO(tangchen): Remove this class and ``ip fixed add`` command
+ # two cycles after Mitaka.
+
+ # This notifies cliff to not display the help for this command
+ deprecated = True
+
+ log = logging.getLogger('deprecated')
+
def get_parser(self, prog_name):
parser = super(AddFixedIP, self).get_parser(prog_name)
parser.add_argument(
"network",
metavar="<network>",
- help="Network to fetch an IP address from (name or ID)",
+ help=_("Network to fetch an IP address from (name or ID)"),
)
parser.add_argument(
"server",
metavar="<server>",
- help="Server to receive the IP address (name or ID)",
+ help=_("Server to receive the IP address (name or ID)"),
)
return parser
def take_action(self, parsed_args):
+ self.log.warning(_('This command has been deprecated. '
+ 'Please use "server add fixed ip" instead.'))
+
compute_client = self.app.client_manager.compute
network = utils.find_resource(
@@ -51,21 +66,32 @@ class AddFixedIP(command.Command):
class RemoveFixedIP(command.Command):
"""Remove fixed IP address from server"""
+ # TODO(tangchen): Remove this class and ``ip fixed remove`` command
+ # two cycles after Mitaka.
+
+ # This notifies cliff to not display the help for this command
+ deprecated = True
+
+ log = logging.getLogger('deprecated')
+
def get_parser(self, prog_name):
parser = super(RemoveFixedIP, self).get_parser(prog_name)
parser.add_argument(
"ip_address",
metavar="<ip-address>",
- help="IP address to remove from server (name only)",
+ help=_("IP address to remove from server (name only)"),
)
parser.add_argument(
"server",
metavar="<server>",
- help="Server to remove the IP address from (name or ID)",
+ help=_("Server to remove the IP address from (name or ID)"),
)
return parser
def take_action(self, parsed_args):
+ self.log.warning(_('This command has been deprecated. '
+ 'Please use "server remove fixed ip" instead.'))
+
compute_client = self.app.client_manager.compute
server = utils.find_resource(
diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py
index 01d7da75..000df598 100644
--- a/openstackclient/compute/v2/flavor.py
+++ b/openstackclient/compute/v2/flavor.py
@@ -122,6 +122,13 @@ class CreateFlavor(command.ShowOne):
help=_("Flavor is not available to other projects")
)
parser.add_argument(
+ "--property",
+ metavar="<key=value>",
+ action=parseractions.KeyValueAction,
+ help=_("Property to add for this flavor "
+ "(repeat option to set multiple properties)")
+ )
+ parser.add_argument(
'--project',
metavar='<project>',
help=_("Allow <project> to access private flavor (name or ID) "
@@ -150,8 +157,7 @@ class CreateFlavor(command.ShowOne):
parsed_args.public
)
- flavor = compute_client.flavors.create(*args)._info.copy()
- flavor.pop("links")
+ flavor = compute_client.flavors.create(*args)
if parsed_args.project:
try:
@@ -166,8 +172,17 @@ class CreateFlavor(command.ShowOne):
msg = _("Failed to add project %(project)s access to "
"flavor: %(e)s")
LOG.error(msg % {'project': parsed_args.project, 'e': e})
+ if parsed_args.property:
+ try:
+ flavor.set_keys(parsed_args.property)
+ except Exception as e:
+ LOG.error(_("Failed to set flavor property: %s"), e)
- return zip(*sorted(six.iteritems(flavor)))
+ flavor_info = flavor._info.copy()
+ flavor_info.pop("links")
+ flavor_info['properties'] = utils.format_dict(flavor.get_keys())
+
+ return zip(*sorted(six.iteritems(flavor_info)))
class DeleteFlavor(command.Command):
diff --git a/openstackclient/compute/v2/floatingip.py b/openstackclient/compute/v2/floatingip.py
index 98079fbc..8398ea57 100644
--- a/openstackclient/compute/v2/floatingip.py
+++ b/openstackclient/compute/v2/floatingip.py
@@ -15,28 +15,43 @@
"""Floating IP action implementations"""
+import logging
+
from osc_lib.command import command
from osc_lib import utils
+from openstackclient.i18n import _
+
class AddFloatingIP(command.Command):
"""Add floating IP address to server"""
+ # TODO(tangchen): Remove this class and ``ip floating add`` command
+ # two cycles after Mitaka.
+
+ # This notifies cliff to not display the help for this command
+ deprecated = True
+
+ log = logging.getLogger('deprecated')
+
def get_parser(self, prog_name):
parser = super(AddFloatingIP, self).get_parser(prog_name)
parser.add_argument(
"ip_address",
metavar="<ip-address>",
- help="IP address to add to server (name only)",
+ help=_("IP address to add to server (name only)"),
)
parser.add_argument(
"server",
metavar="<server>",
- help="Server to receive the IP address (name or ID)",
+ help=_("Server to receive the IP address (name or ID)"),
)
return parser
def take_action(self, parsed_args):
+ self.log.warning(_('This command has been deprecated. '
+ 'Please use "server add floating ip" instead.'))
+
compute_client = self.app.client_manager.compute
server = utils.find_resource(
@@ -48,21 +63,32 @@ class AddFloatingIP(command.Command):
class RemoveFloatingIP(command.Command):
"""Remove floating IP address from server"""
+ # TODO(tangchen): Remove this class and ``ip floating remove`` command
+ # two cycles after Mitaka.
+
+ # This notifies cliff to not display the help for this command
+ deprecated = True
+
+ log = logging.getLogger('deprecated')
+
def get_parser(self, prog_name):
parser = super(RemoveFloatingIP, self).get_parser(prog_name)
parser.add_argument(
"ip_address",
metavar="<ip-address>",
- help="IP address to remove from server (name only)",
+ help=_("IP address to remove from server (name only)"),
)
parser.add_argument(
"server",
metavar="<server>",
- help="Server to remove the IP address from (name or ID)",
+ help=_("Server to remove the IP address from (name or ID)"),
)
return parser
def take_action(self, parsed_args):
+ self.log.warning(_('This command has been deprecated. '
+ 'Please use "server remove floating ip" instead.'))
+
compute_client = self.app.client_manager.compute
server = utils.find_resource(
diff --git a/openstackclient/compute/v2/floatingippool.py b/openstackclient/compute/v2/floatingippool.py
deleted file mode 100644
index 0d46e32b..00000000
--- a/openstackclient/compute/v2/floatingippool.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-"""Floating IP Pool action implementations"""
-
-from osc_lib.command import command
-from osc_lib import utils
-
-
-class ListFloatingIPPool(command.Lister):
- """List pools of floating IP addresses"""
-
- def take_action(self, parsed_args):
- compute_client = self.app.client_manager.compute
-
- columns = ('Name',)
-
- data = compute_client.floating_ip_pools.list()
-
- return (columns,
- (utils.get_item_properties(
- s, columns,
- formatters={},
- ) for s in data))
diff --git a/openstackclient/compute/v2/keypair.py b/openstackclient/compute/v2/keypair.py
index 3725a3a8..d30fd429 100644
--- a/openstackclient/compute/v2/keypair.py
+++ b/openstackclient/compute/v2/keypair.py
@@ -146,7 +146,7 @@ class ShowKeypair(command.ShowOne):
'--public-key',
action='store_true',
default=False,
- help=_("Show only bare public key")
+ help=_("Show only bare public key (name only)")
)
return parser
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 7e4b0dc1..a317c11d 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -174,6 +174,63 @@ def _show_progress(progress):
sys.stdout.flush()
+class AddFixedIP(command.Command):
+ """Add fixed IP address to server"""
+
+ def get_parser(self, prog_name):
+ parser = super(AddFixedIP, self).get_parser(prog_name)
+ parser.add_argument(
+ "server",
+ metavar="<server>",
+ help=_("Server (name or ID) to receive the fixed IP address"),
+ )
+ parser.add_argument(
+ "network",
+ metavar="<network>",
+ help=_("Network (name or ID) to allocate "
+ "the fixed IP address from"),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+
+ server = utils.find_resource(
+ compute_client.servers, parsed_args.server)
+
+ network = utils.find_resource(
+ compute_client.networks, parsed_args.network)
+
+ server.add_fixed_ip(network.id)
+
+
+class AddFloatingIP(command.Command):
+ """Add floating IP address to server"""
+
+ def get_parser(self, prog_name):
+ parser = super(AddFloatingIP, self).get_parser(prog_name)
+ parser.add_argument(
+ "server",
+ metavar="<server>",
+ help=_("Server (name or ID) to receive the floating IP address"),
+ )
+ parser.add_argument(
+ "ip_address",
+ metavar="<ip-address>",
+ help=_("Floating IP address (IP address only) to assign "
+ "to server"),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+
+ server = utils.find_resource(
+ compute_client.servers, parsed_args.server)
+
+ server.add_floating_ip(parsed_args.ip_address)
+
+
class AddServerSecurityGroup(command.Command):
"""Add security group to server"""
@@ -1081,6 +1138,61 @@ class RebuildServer(command.ShowOne):
return zip(*sorted(six.iteritems(details)))
+class RemoveFixedIP(command.Command):
+ """Remove fixed IP address from server"""
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveFixedIP, self).get_parser(prog_name)
+ parser.add_argument(
+ "server",
+ metavar="<server>",
+ help=_("Server (name or ID) to remove the fixed IP address from"),
+ )
+ parser.add_argument(
+ "ip_address",
+ metavar="<ip-address>",
+ help=_("Fixed IP address (IP address only) to remove from the "
+ "server"),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+
+ server = utils.find_resource(
+ compute_client.servers, parsed_args.server)
+
+ server.remove_fixed_ip(parsed_args.ip_address)
+
+
+class RemoveFloatingIP(command.Command):
+ """Remove floating IP address from server"""
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveFloatingIP, self).get_parser(prog_name)
+ parser.add_argument(
+ "server",
+ metavar="<server>",
+ help=_("Server (name or ID) to remove the "
+ "floating IP address from"),
+ )
+ parser.add_argument(
+ "ip_address",
+ metavar="<ip-address>",
+ help=_("Floating IP address (IP address only) "
+ "to remove from server"),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+
+ server = utils.find_resource(
+ compute_client.servers, parsed_args.server)
+
+ server.remove_floating_ip(parsed_args.ip_address)
+
+
class RemoveServerSecurityGroup(command.Command):
"""Remove security group from server"""
@@ -1110,7 +1222,7 @@ class RemoveServerSecurityGroup(command.Command):
parsed_args.group,
)
- server.remove_security_group(security_group)
+ server.remove_security_group(security_group.id)
class RemoveServerVolume(command.Command):
diff --git a/openstackclient/identity/client.py b/openstackclient/identity/client.py
index be7b643f..d932b970 100644
--- a/openstackclient/identity/client.py
+++ b/openstackclient/identity/client.py
@@ -16,9 +16,9 @@
import logging
from keystoneclient.v2_0 import client as identity_client_v2
+from osc_lib.api import auth
from osc_lib import utils
-from openstackclient.api import auth
from openstackclient.i18n import _
LOG = logging.getLogger(__name__)
diff --git a/openstackclient/identity/v2_0/ec2creds.py b/openstackclient/identity/v2_0/ec2creds.py
index 058b5772..4873cd55 100644
--- a/openstackclient/identity/v2_0/ec2creds.py
+++ b/openstackclient/identity/v2_0/ec2creds.py
@@ -94,7 +94,7 @@ class DeleteEC2Creds(command.Command):
'access_keys',
metavar='<access-key>',
nargs='+',
- help=_('Credentials access keys'),
+ help=_('Credentials access key(s)'),
)
parser.add_argument(
'--user',
@@ -121,7 +121,7 @@ class DeleteEC2Creds(command.Command):
identity_client.ec2.delete(user, access_key)
except Exception as e:
result += 1
- LOG.error(_("Failed to delete EC2 keys with "
+ LOG.error(_("Failed to delete EC2 credentials with "
"access key '%(access_key)s': %(e)s")
% {'access_key': access_key, 'e': e})
diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py
index 6c5db13c..fc5c9201 100644..100755
--- a/openstackclient/identity/v2_0/project.py
+++ b/openstackclient/identity/v2_0/project.py
@@ -86,7 +86,7 @@ class CreateProject(command.ShowOne):
enabled=enabled,
**kwargs
)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
project = utils.find_resource(
identity_client.tenants,
@@ -94,7 +94,7 @@ class CreateProject(command.ShowOne):
)
LOG.info(_('Returning existing project %s'), project.name)
else:
- raise e
+ raise
# TODO(stevemar): Remove the line below when we support multitenancy
project._info.pop('parent_id', None)
@@ -242,7 +242,7 @@ class ShowProject(command.ShowOne):
parsed_args.project,
)
info.update(project._info)
- except ks_exc.Forbidden as e:
+ except ks_exc.Forbidden:
auth_ref = self.app.client_manager.auth_ref
if (
parsed_args.project == auth_ref.project_id or
@@ -256,7 +256,7 @@ class ShowProject(command.ShowOne):
'enabled': True,
}
else:
- raise e
+ raise
# TODO(stevemar): Remove the line below when we support multitenancy
info.pop('parent_id', None)
diff --git a/openstackclient/identity/v2_0/role.py b/openstackclient/identity/v2_0/role.py
index 6d06230c..191cdaa3 100644..100755
--- a/openstackclient/identity/v2_0/role.py
+++ b/openstackclient/identity/v2_0/role.py
@@ -93,7 +93,7 @@ class CreateRole(command.ShowOne):
identity_client = self.app.client_manager.identity
try:
role = identity_client.roles.create(parsed_args.role_name)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
role = utils.find_resource(
identity_client.roles,
@@ -101,7 +101,7 @@ class CreateRole(command.ShowOne):
)
LOG.info(_('Returning existing role %s'), role.name)
else:
- raise e
+ raise
info = {}
info.update(role._info)
diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py
index 0f327830..d2075150 100644..100755
--- a/openstackclient/identity/v2_0/user.py
+++ b/openstackclient/identity/v2_0/user.py
@@ -102,7 +102,7 @@ class CreateUser(command.ShowOne):
tenant_id=project_id,
enabled=enabled,
)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
user = utils.find_resource(
identity_client.users,
@@ -110,7 +110,7 @@ class CreateUser(command.ShowOne):
)
LOG.info(_('Returning existing user %s'), user.name)
else:
- raise e
+ raise
# NOTE(dtroyer): The users.create() method wants 'tenant_id' but
# the returned resource has 'tenantId'. Sigh.
@@ -349,7 +349,7 @@ class ShowUser(command.ShowOne):
parsed_args.user,
)
info.update(user._info)
- except ks_exc.Forbidden as e:
+ except ks_exc.Forbidden:
auth_ref = self.app.client_manager.auth_ref
if (
parsed_args.user == auth_ref.user_id or
@@ -364,7 +364,7 @@ class ShowUser(command.ShowOne):
'enabled': True,
}
else:
- raise e
+ raise
if 'tenantId' in info:
info.update(
diff --git a/openstackclient/identity/v3/consumer.py b/openstackclient/identity/v3/consumer.py
index a4620bf9..b41a37ca 100644
--- a/openstackclient/identity/v3/consumer.py
+++ b/openstackclient/identity/v3/consumer.py
@@ -15,15 +15,19 @@
"""Identity v3 Consumer action implementations"""
-import sys
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateConsumer(command.ShowOne):
"""Create new consumer"""
@@ -46,22 +50,37 @@ class CreateConsumer(command.ShowOne):
class DeleteConsumer(command.Command):
- """Delete consumer"""
+ """Delete consumer(s)"""
def get_parser(self, prog_name):
parser = super(DeleteConsumer, self).get_parser(prog_name)
parser.add_argument(
'consumer',
metavar='<consumer>',
- help=_('Consumer to delete'),
+ nargs='+',
+ help=_('Consumer(s) to delete'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- consumer = utils.find_resource(
- identity_client.oauth1.consumers, parsed_args.consumer)
- identity_client.oauth1.consumers.delete(consumer.id)
+ result = 0
+ for i in parsed_args.consumer:
+ try:
+ consumer = utils.find_resource(
+ identity_client.oauth1.consumers, i)
+ identity_client.oauth1.consumers.delete(consumer.id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete consumer with name or "
+ "ID '%(consumer)s': %(e)s")
+ % {'consumer': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.consumer)
+ msg = (_("%(result)s of %(total)s consumers failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListConsumer(command.Lister):
@@ -102,10 +121,6 @@ class SetConsumer(command.Command):
if parsed_args.description:
kwargs['description'] = parsed_args.description
- if not len(kwargs):
- sys.stdout.write(_('Consumer not updated, no arguments present\n'))
- return
-
consumer = identity_client.oauth1.consumers.update(
consumer.id, **kwargs)
diff --git a/openstackclient/identity/v3/credential.py b/openstackclient/identity/v3/credential.py
index eeeddfa5..0ef94cf4 100644
--- a/openstackclient/identity/v3/credential.py
+++ b/openstackclient/identity/v3/credential.py
@@ -15,22 +15,28 @@
"""Identity v3 Credential action implementations"""
+import logging
+
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateCredential(command.ShowOne):
- """Create credential command"""
+ """Create new credential"""
def get_parser(self, prog_name):
parser = super(CreateCredential, self).get_parser(prog_name)
parser.add_argument(
'user',
metavar='<user>',
- help=_('Name or ID of user that owns the credential'),
+ help=_('user that owns the credential (name or ID)'),
)
parser.add_argument(
'--type',
@@ -47,8 +53,8 @@ class CreateCredential(command.ShowOne):
parser.add_argument(
'--project',
metavar='<project>',
- help=_('Project name or ID which limits the '
- 'scope of the credential'),
+ help=_('Project which limits the scope of '
+ 'the credential (name or ID)'),
)
return parser
@@ -72,24 +78,39 @@ class CreateCredential(command.ShowOne):
class DeleteCredential(command.Command):
- """Delete credential command"""
+ """Delete credential(s)"""
def get_parser(self, prog_name):
parser = super(DeleteCredential, self).get_parser(prog_name)
parser.add_argument(
'credential',
metavar='<credential-id>',
- help=_('ID of credential to delete'),
+ nargs='+',
+ help=_('ID of credential(s) to delete'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- identity_client.credentials.delete(parsed_args.credential)
+ result = 0
+ for i in parsed_args.credential:
+ try:
+ identity_client.credentials.delete(i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete credentials with "
+ "ID '%(credential)s': %(e)s")
+ % {'credential': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.credential)
+ msg = (_("%(result)s of %(total)s credential failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListCredential(command.Lister):
- """List credential command"""
+ """List credentials"""
def take_action(self, parsed_args):
columns = ('ID', 'Type', 'User ID', 'Blob', 'Project ID')
@@ -103,7 +124,7 @@ class ListCredential(command.Lister):
class SetCredential(command.Command):
- """Set credential command"""
+ """Set credential properties"""
def get_parser(self, prog_name):
parser = super(SetCredential, self).get_parser(prog_name)
@@ -116,7 +137,7 @@ class SetCredential(command.Command):
'--user',
metavar='<user>',
required=True,
- help=_('Name or ID of user that owns the credential'),
+ help=_('User that owns the credential (name or ID)'),
)
parser.add_argument(
'--type',
@@ -134,8 +155,8 @@ class SetCredential(command.Command):
parser.add_argument(
'--project',
metavar='<project>',
- help=_('Project name or ID which limits the '
- 'scope of the credential'),
+ help=_('Project which limits the scope of '
+ 'the credential (name or ID)'),
)
return parser
@@ -159,7 +180,7 @@ class SetCredential(command.Command):
class ShowCredential(command.ShowOne):
- """Show credential command"""
+ """Display credential details"""
def get_parser(self, prog_name):
parser = super(ShowCredential, self).get_parser(prog_name)
diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py
index 8ba76c41..76e47d32 100644..100755
--- a/openstackclient/identity/v3/domain.py
+++ b/openstackclient/identity/v3/domain.py
@@ -16,10 +16,10 @@
"""Identity v3 Domain action implementations"""
import logging
-import sys
from keystoneauth1 import exceptions as ks_exc
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -76,35 +76,49 @@ class CreateDomain(command.ShowOne):
description=parsed_args.description,
enabled=enabled,
)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
domain = utils.find_resource(identity_client.domains,
parsed_args.name)
LOG.info(_('Returning existing domain %s'), domain.name)
else:
- raise e
+ raise
domain._info.pop('links')
return zip(*sorted(six.iteritems(domain._info)))
class DeleteDomain(command.Command):
- """Delete domain"""
+ """Delete domain(s)"""
def get_parser(self, prog_name):
parser = super(DeleteDomain, self).get_parser(prog_name)
parser.add_argument(
'domain',
metavar='<domain>',
- help=_('Domain to delete (name or ID)'),
+ nargs='+',
+ help=_('Domain(s) to delete (name or ID)'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- domain = utils.find_resource(identity_client.domains,
- parsed_args.domain)
- identity_client.domains.delete(domain.id)
+ result = 0
+ for i in parsed_args.domain:
+ try:
+ domain = utils.find_resource(identity_client.domains, i)
+ identity_client.domains.delete(domain.id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete domain with name or "
+ "ID '%(domain)s': %(e)s")
+ % {'domain': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.domain)
+ msg = (_("%(result)s of %(total)s domains failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListDomain(command.Lister):
@@ -168,9 +182,6 @@ class SetDomain(command.Command):
if parsed_args.disable:
kwargs['enabled'] = False
- if not kwargs:
- sys.stdout.write(_("Domain not updated, no arguments present\n"))
- return
identity_client.domains.update(domain.id, **kwargs)
diff --git a/openstackclient/identity/v3/ec2creds.py b/openstackclient/identity/v3/ec2creds.py
index 835fe96f..7ad01719 100644
--- a/openstackclient/identity/v3/ec2creds.py
+++ b/openstackclient/identity/v3/ec2creds.py
@@ -12,7 +12,10 @@
"""Identity v3 EC2 Credentials action implementations"""
+import logging
+
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -20,6 +23,9 @@ from openstackclient.i18n import _
from openstackclient.identity import common
+LOG = logging.getLogger(__name__)
+
+
def _determine_ec2_user(parsed_args, client_manager):
"""Determine a user several different ways.
@@ -113,7 +119,8 @@ class DeleteEC2Creds(command.Command):
parser.add_argument(
'access_key',
metavar='<access-key>',
- help=_('Credentials access key'),
+ nargs='+',
+ help=_('Credentials access key(s)'),
)
parser.add_argument(
'--user',
@@ -126,7 +133,21 @@ class DeleteEC2Creds(command.Command):
def take_action(self, parsed_args):
client_manager = self.app.client_manager
user = _determine_ec2_user(parsed_args, client_manager)
- client_manager.identity.ec2.delete(user, parsed_args.access_key)
+ result = 0
+ for i in parsed_args.access_key:
+ try:
+ client_manager.identity.ec2.delete(user, i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete EC2 credentials with "
+ "access key '%(access_key)s': %(e)s")
+ % {'access_key': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.access_key)
+ msg = (_("%(result)s of %(total)s EC2 keys failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListEC2Creds(command.Lister):
diff --git a/openstackclient/identity/v3/endpoint.py b/openstackclient/identity/v3/endpoint.py
index 2f1cc9f3..73b37a43 100644
--- a/openstackclient/identity/v3/endpoint.py
+++ b/openstackclient/identity/v3/endpoint.py
@@ -15,9 +15,10 @@
"""Identity v3 Endpoint action implementations"""
-import sys
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -25,6 +26,9 @@ from openstackclient.i18n import _
from openstackclient.identity import common
+LOG = logging.getLogger(__name__)
+
+
def get_service_name(service):
if hasattr(service, 'name'):
return service.name
@@ -95,22 +99,37 @@ class CreateEndpoint(command.ShowOne):
class DeleteEndpoint(command.Command):
- """Delete endpoint"""
+ """Delete endpoint(s)"""
def get_parser(self, prog_name):
parser = super(DeleteEndpoint, self).get_parser(prog_name)
parser.add_argument(
'endpoint',
metavar='<endpoint-id>',
- help=_('Endpoint to delete (ID only)'),
+ nargs='+',
+ help=_('Endpoint(s) to delete (ID only)'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- endpoint_id = utils.find_resource(identity_client.endpoints,
- parsed_args.endpoint).id
- identity_client.endpoints.delete(endpoint_id)
+ result = 0
+ for i in parsed_args.endpoint:
+ try:
+ endpoint_id = utils.find_resource(
+ identity_client.endpoints, i).id
+ identity_client.endpoints.delete(endpoint_id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete endpoint with "
+ "ID '%(endpoint)s': %(e)s")
+ % {'endpoint': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.endpoint)
+ msg = (_("%(result)s of %(total)s endpoints failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListEndpoint(command.Lister):
@@ -212,12 +231,6 @@ class SetEndpoint(command.Command):
endpoint = utils.find_resource(identity_client.endpoints,
parsed_args.endpoint)
- if (not parsed_args.interface and not parsed_args.url
- and not parsed_args.service and not parsed_args.region
- and not parsed_args.enabled and not parsed_args.disabled):
- sys.stdout.write(_("Endpoint not updated, no arguments present\n"))
- return
-
service_id = None
if parsed_args.service:
service = common.find_service(identity_client, parsed_args.service)
diff --git a/openstackclient/identity/v3/federation_protocol.py b/openstackclient/identity/v3/federation_protocol.py
index 09480245..3fde9027 100644
--- a/openstackclient/identity/v3/federation_protocol.py
+++ b/openstackclient/identity/v3/federation_protocol.py
@@ -17,6 +17,7 @@
import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -71,14 +72,15 @@ class CreateProtocol(command.ShowOne):
class DeleteProtocol(command.Command):
- """Delete federation protocol"""
+ """Delete federation protocol(s)"""
def get_parser(self, prog_name):
parser = super(DeleteProtocol, self).get_parser(prog_name)
parser.add_argument(
'federation_protocol',
metavar='<federation-protocol>',
- help=_('Federation protocol to delete (name or ID)'),
+ nargs='+',
+ help=_('Federation protocol(s) to delete (name or ID)'),
)
parser.add_argument(
'--identity-provider',
@@ -92,8 +94,22 @@ class DeleteProtocol(command.Command):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- identity_client.federation.protocols.delete(
- parsed_args.identity_provider, parsed_args.federation_protocol)
+ result = 0
+ for i in parsed_args.federation_protocol:
+ try:
+ identity_client.federation.protocols.delete(
+ parsed_args.identity_provider, i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete federation protocol "
+ "with name or ID '%(protocol)s': %(e)s")
+ % {'protocol': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.federation_protocol)
+ msg = (_("%(result)s of %(total)s federation protocols failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListProtocols(command.Lister):
@@ -149,10 +165,6 @@ class SetProtocol(command.Command):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- if not parsed_args.mapping:
- LOG.error(_("No changes requested"))
- return
-
protocol = identity_client.federation.protocols.update(
parsed_args.identity_provider, parsed_args.federation_protocol,
parsed_args.mapping)
diff --git a/openstackclient/identity/v3/group.py b/openstackclient/identity/v3/group.py
index 8351fe64..f780810a 100644..100755
--- a/openstackclient/identity/v3/group.py
+++ b/openstackclient/identity/v3/group.py
@@ -160,14 +160,14 @@ class CreateGroup(command.ShowOne):
name=parsed_args.name,
domain=domain,
description=parsed_args.description)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
group = utils.find_resource(identity_client.groups,
parsed_args.name,
domain_id=domain)
LOG.info(_('Returning existing group %s'), group.name)
else:
- raise e
+ raise
group._info.pop('links')
return zip(*sorted(six.iteritems(group._info)))
@@ -343,9 +343,6 @@ class SetGroup(command.Command):
if parsed_args.description:
kwargs['description'] = parsed_args.description
- if not len(kwargs):
- sys.stderr.write("Group not updated, no arguments present\n")
- return
identity_client.groups.update(group.id, **kwargs)
diff --git a/openstackclient/identity/v3/identity_provider.py b/openstackclient/identity/v3/identity_provider.py
index 5c638f9b..0453e888 100644
--- a/openstackclient/identity/v3/identity_provider.py
+++ b/openstackclient/identity/v3/identity_provider.py
@@ -16,6 +16,7 @@
import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -93,21 +94,35 @@ class CreateIdentityProvider(command.ShowOne):
class DeleteIdentityProvider(command.Command):
- """Delete identity provider"""
+ """Delete identity provider(s)"""
def get_parser(self, prog_name):
parser = super(DeleteIdentityProvider, self).get_parser(prog_name)
parser.add_argument(
'identity_provider',
metavar='<identity-provider>',
- help=_('Identity provider to delete'),
+ nargs='+',
+ help=_('Identity provider(s) to delete'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- identity_client.federation.identity_providers.delete(
- parsed_args.identity_provider)
+ result = 0
+ for i in parsed_args.identity_provider:
+ try:
+ identity_client.federation.identity_providers.delete(i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete identity providers with "
+ "name or ID '%(provider)s': %(e)s")
+ % {'provider': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.identity_provider)
+ msg = (_("%(result)s of %(total)s identity providers failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListIdentityProvider(command.Lister):
@@ -169,14 +184,6 @@ class SetIdentityProvider(command.Command):
def take_action(self, parsed_args):
federation_client = self.app.client_manager.identity.federation
- # Basic argument checking
- if (not parsed_args.enable and not parsed_args.disable and
- not parsed_args.remote_id and
- not parsed_args.remote_id_file and
- not parsed_args.description):
- LOG.error(_('No changes requested'))
- return (None, None)
-
# Always set remote_ids if either is passed in
if parsed_args.remote_id_file:
file_content = utils.read_blob_file_contents(
diff --git a/openstackclient/identity/v3/mapping.py b/openstackclient/identity/v3/mapping.py
index 74ead228..09181a0b 100644
--- a/openstackclient/identity/v3/mapping.py
+++ b/openstackclient/identity/v3/mapping.py
@@ -111,21 +111,35 @@ class CreateMapping(command.ShowOne, _RulesReader):
class DeleteMapping(command.Command):
- """Delete mapping"""
+ """Delete mapping(s)"""
def get_parser(self, prog_name):
parser = super(DeleteMapping, self).get_parser(prog_name)
parser.add_argument(
'mapping',
metavar='<mapping>',
- help=_('Mapping to delete'),
+ nargs='+',
+ help=_('Mapping(s) to delete'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
-
- identity_client.federation.mappings.delete(parsed_args.mapping)
+ result = 0
+ for i in parsed_args.mapping:
+ try:
+ identity_client.federation.mappings.delete(i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete mapping with name or "
+ "ID '%(mapping)s': %(e)s")
+ % {'mapping': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.mapping)
+ msg = (_("%(result)s of %(total)s mappings failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListMapping(command.Lister):
@@ -162,10 +176,6 @@ class SetMapping(command.Command, _RulesReader):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- if not parsed_args.rules:
- LOG.error(_("No changes requested"))
- return
-
rules = self._read_rules(parsed_args.rules)
mapping = identity_client.federation.mappings.update(
diff --git a/openstackclient/identity/v3/policy.py b/openstackclient/identity/v3/policy.py
index 68fb2738..596eae01 100644
--- a/openstackclient/identity/v3/policy.py
+++ b/openstackclient/identity/v3/policy.py
@@ -15,15 +15,19 @@
"""Identity v3 Policy action implementations"""
-import sys
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreatePolicy(command.ShowOne):
"""Create new policy"""
@@ -57,20 +61,35 @@ class CreatePolicy(command.ShowOne):
class DeletePolicy(command.Command):
- """Delete policy"""
+ """Delete policy(s)"""
def get_parser(self, prog_name):
parser = super(DeletePolicy, self).get_parser(prog_name)
parser.add_argument(
'policy',
metavar='<policy>',
- help=_('Policy to delete'),
+ nargs='+',
+ help=_('Policy(s) to delete'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- identity_client.policies.delete(parsed_args.policy)
+ result = 0
+ for i in parsed_args.policy:
+ try:
+ identity_client.policies.delete(i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete policy with name or "
+ "ID '%(policy)s': %(e)s")
+ % {'policy': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.policy)
+ msg = (_("%(result)s of %(total)s policys failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListPolicy(command.Lister):
@@ -136,9 +155,6 @@ class SetPolicy(command.Command):
if parsed_args.type:
kwargs['type'] = parsed_args.type
- if not kwargs:
- sys.stdout.write(_('Policy not updated, no arguments present\n'))
- return
identity_client.policies.update(parsed_args.policy, **kwargs)
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 56c1d41a..56c4fbc8 100644..100755
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -111,14 +111,14 @@ class CreateProject(command.ShowOne):
enabled=enabled,
**kwargs
)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
project = utils.find_resource(identity_client.projects,
parsed_args.name,
domain_id=domain)
LOG.info(_('Returning existing project %s'), project.name)
else:
- raise e
+ raise
project._info.pop('links')
return zip(*sorted(six.iteritems(project._info)))
@@ -263,13 +263,6 @@ class SetProject(command.Command):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- if (not parsed_args.name
- and not parsed_args.domain
- and not parsed_args.description
- and not parsed_args.enable
- and not parsed_args.property
- and not parsed_args.disable):
- return
project = common.find_project(identity_client,
parsed_args.project,
parsed_args.domain)
diff --git a/openstackclient/identity/v3/region.py b/openstackclient/identity/v3/region.py
index b5e46a9a..b7c51f93 100644
--- a/openstackclient/identity/v3/region.py
+++ b/openstackclient/identity/v3/region.py
@@ -13,13 +13,19 @@
"""Identity v3 Region action implementations"""
+import logging
+
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateRegion(command.ShowOne):
"""Create new region"""
@@ -60,21 +66,35 @@ class CreateRegion(command.ShowOne):
class DeleteRegion(command.Command):
- """Delete region"""
+ """Delete region(s)"""
def get_parser(self, prog_name):
parser = super(DeleteRegion, self).get_parser(prog_name)
parser.add_argument(
'region',
metavar='<region-id>',
- help=_('Region ID to delete'),
+ nargs='+',
+ help=_('Region ID(s) to delete'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
-
- identity_client.regions.delete(parsed_args.region)
+ result = 0
+ for i in parsed_args.region:
+ try:
+ identity_client.regions.delete(i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete region with "
+ "ID '%(region)s': %(e)s")
+ % {'region': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.region)
+ msg = (_("%(result)s of %(total)s regions failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListRegion(command.Lister):
@@ -132,8 +152,6 @@ class SetRegion(command.Command):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- if not parsed_args.parent_region and not parsed_args.description:
- return
kwargs = {}
if parsed_args.description:
kwargs['description'] = parsed_args.description
diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py
index 965ca3f5..27380179 100644..100755
--- a/openstackclient/identity/v3/role.py
+++ b/openstackclient/identity/v3/role.py
@@ -165,13 +165,13 @@ class CreateRole(command.ShowOne):
try:
role = identity_client.roles.create(name=parsed_args.name)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
role = utils.find_resource(identity_client.roles,
parsed_args.name)
LOG.info(_('Returning existing role %s'), role.name)
else:
- raise e
+ raise
role._info.pop('links')
return zip(*sorted(six.iteritems(role._info)))
@@ -357,10 +357,6 @@ class SetRole(command.Command):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- if not parsed_args.name:
- sys.stderr.write(_("Incorrect set of arguments provided. "
- "See openstack --help for more details\n"))
- return
role = utils.find_resource(
identity_client.roles,
parsed_args.role,
diff --git a/openstackclient/identity/v3/service.py b/openstackclient/identity/v3/service.py
index 195b2701..97e64dc6 100644
--- a/openstackclient/identity/v3/service.py
+++ b/openstackclient/identity/v3/service.py
@@ -15,9 +15,10 @@
"""Identity v3 Service action implementations"""
-import sys
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -25,6 +26,9 @@ from openstackclient.i18n import _
from openstackclient.identity import common
+LOG = logging.getLogger(__name__)
+
+
class CreateService(command.ShowOne):
"""Create new service"""
@@ -77,23 +81,36 @@ class CreateService(command.ShowOne):
class DeleteService(command.Command):
- """Delete service"""
+ """Delete service(s)"""
def get_parser(self, prog_name):
parser = super(DeleteService, self).get_parser(prog_name)
parser.add_argument(
'service',
metavar='<service>',
- help=_('Service to delete (type, name or ID)'),
+ nargs='+',
+ help=_('Service(s) to delete (type, name or ID)'),
)
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
-
- service = common.find_service(identity_client, parsed_args.service)
-
- identity_client.services.delete(service.id)
+ result = 0
+ for i in parsed_args.service:
+ try:
+ service = common.find_service(identity_client, i)
+ identity_client.services.delete(service.id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete consumer with type, "
+ "name or ID '%(service)s': %(e)s")
+ % {'service': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.service)
+ msg = (_("%(result)s of %(total)s services failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListService(command.Lister):
@@ -163,14 +180,6 @@ class SetService(command.Command):
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
- if (not parsed_args.name
- and not parsed_args.type
- and not parsed_args.description
- and not parsed_args.enable
- and not parsed_args.disable):
- sys.stderr.write(_("Incorrect set of arguments provided. "
- "See openstack --help for more details\n"))
- return
service = common.find_service(identity_client,
parsed_args.service)
kwargs = {}
diff --git a/openstackclient/identity/v3/service_provider.py b/openstackclient/identity/v3/service_provider.py
index 0beea813..440eba40 100644
--- a/openstackclient/identity/v3/service_provider.py
+++ b/openstackclient/identity/v3/service_provider.py
@@ -13,15 +13,19 @@
"""Service Provider action implementations"""
-import sys
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateServiceProvider(command.ShowOne):
"""Create new service provider"""
@@ -83,21 +87,35 @@ class CreateServiceProvider(command.ShowOne):
class DeleteServiceProvider(command.Command):
- """Delete service provider"""
+ """Delete service provider(s)"""
def get_parser(self, prog_name):
parser = super(DeleteServiceProvider, self).get_parser(prog_name)
parser.add_argument(
'service_provider',
metavar='<service-provider>',
- help=_('Service provider to delete'),
+ nargs='+',
+ help=_('Service provider(s) to delete'),
)
return parser
def take_action(self, parsed_args):
service_client = self.app.client_manager.identity
- service_client.federation.service_providers.delete(
- parsed_args.service_provider)
+ result = 0
+ for i in parsed_args.service_provider:
+ try:
+ service_client.federation.service_providers.delete(i)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete service provider with "
+ "name or ID '%(provider)s': %(e)s")
+ % {'provider': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.service_provider)
+ msg = (_("%(result)s of %(total)s service providers failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListServiceProvider(command.Lister):
@@ -164,13 +182,6 @@ class SetServiceProvider(command.Command):
elif parsed_args.disable is True:
enabled = False
- if not any((enabled is not None, parsed_args.description,
- parsed_args.service_provider_url,
- parsed_args.auth_url)):
- sys.stdout.write(_("Service Provider not updated, no arguments "
- "present\n"))
- return (None, None)
-
service_provider = federation_client.service_providers.update(
parsed_args.service_provider, enabled=enabled,
description=parsed_args.description,
diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py
index dd5af06a..dc47ef8d 100644..100755
--- a/openstackclient/identity/v3/user.py
+++ b/openstackclient/identity/v3/user.py
@@ -17,7 +17,6 @@
import copy
import logging
-import sys
from keystoneauth1 import exceptions as ks_exc
from osc_lib.command import command
@@ -121,14 +120,14 @@ class CreateUser(command.ShowOne):
description=parsed_args.description,
enabled=enabled
)
- except ks_exc.Conflict as e:
+ except ks_exc.Conflict:
if parsed_args.or_show:
user = utils.find_resource(identity_client.users,
parsed_args.name,
domain_id=domain_id)
LOG.info(_('Returning existing user %s'), user.name)
else:
- raise e
+ raise
user._info.pop('links')
return zip(*sorted(six.iteritems(user._info)))
@@ -330,18 +329,6 @@ class SetUser(command.Command):
if parsed_args.password_prompt:
parsed_args.password = utils.get_password(self.app.stdin)
- if (not parsed_args.name
- and not parsed_args.name
- and not parsed_args.password
- and not parsed_args.email
- and not parsed_args.project
- and not parsed_args.description
- and not parsed_args.enable
- and not parsed_args.disable):
- sys.stderr.write(_("Incorrect set of arguments provided. "
- "See openstack --help for more details\n"))
- return
-
user = utils.find_resource(
identity_client.users,
parsed_args.user,
diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py
index e7b60e5a..5f669c64 100644
--- a/openstackclient/image/v1/image.py
+++ b/openstackclient/image/v1/image.py
@@ -378,6 +378,7 @@ class ListImage(command.Lister):
'Disk Format',
'Container Format',
'Size',
+ 'Checksum',
'Status',
'is_public',
'protected',
@@ -390,6 +391,7 @@ class ListImage(command.Lister):
'Disk Format',
'Container Format',
'Size',
+ 'Checksum',
'Status',
'Visibility',
'Protected',
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index 309b1b6b..0712e09c 100644..100755
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -339,7 +339,7 @@ class CreateImage(command.ShowOne):
with fp:
try:
image_client.images.upload(image.id, fp)
- except Exception as e:
+ except Exception:
# If the upload fails for some reason attempt to remove the
# dangling queued image made by the create() call above but
# only if the user did not specify an id which indicates
@@ -349,7 +349,7 @@ class CreateImage(command.ShowOne):
image_client.images.delete(image.id)
except Exception:
pass # we don't care about this one
- raise e # now, throw the upload exception again
+ raise # now, throw the upload exception again
# update the image after the data has been uploaded
image = image_client.images.get(image.id)
@@ -490,6 +490,7 @@ class ListImage(command.Lister):
'Disk Format',
'Container Format',
'Size',
+ 'Checksum',
'Status',
'visibility',
'protected',
@@ -502,6 +503,7 @@ class ListImage(command.Lister):
'Disk Format',
'Container Format',
'Size',
+ 'Checksum',
'Status',
'Visibility',
'Protected',
@@ -834,11 +836,11 @@ class SetImage(command.Command):
try:
image = image_client.images.update(image.id, **kwargs)
- except Exception as e:
+ except Exception:
if activation_status is not None:
LOG.info(_("Image %(id)s was %(status)s."),
{'id': image.id, 'status': activation_status})
- raise e
+ raise
class ShowImage(command.ShowOne):
diff --git a/openstackclient/network/common.py b/openstackclient/network/common.py
index f62840fc..2b1a5656 100644
--- a/openstackclient/network/common.py
+++ b/openstackclient/network/common.py
@@ -111,7 +111,7 @@ class NetworkAndComputeDelete(NetworkAndComputeCommand):
if ret:
total = len(resources)
- msg = _("%(num)s of %(total)s %(resource)s failed to delete.") % {
+ msg = _("%(num)s of %(total)s %(resource)ss failed to delete.") % {
"num": ret,
"total": total,
"resource": self.resource,
diff --git a/openstackclient/network/v2/floating_ip_pool.py b/openstackclient/network/v2/floating_ip_pool.py
new file mode 100644
index 00000000..c78ca06a
--- /dev/null
+++ b/openstackclient/network/v2/floating_ip_pool.py
@@ -0,0 +1,66 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+"""Floating IP Pool action implementations"""
+
+import logging
+
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.i18n import _
+from openstackclient.network import common
+
+
+class ListFloatingIPPool(common.NetworkAndComputeLister):
+ """List pools of floating IP addresses"""
+
+ def take_action_network(self, client, parsed_args):
+ msg = _("Floating ip pool operations are only available for "
+ "Compute v2 network.")
+ raise exceptions.CommandError(msg)
+
+ def take_action_compute(self, client, parsed_args):
+ columns = (
+ 'Name',
+ )
+ data = client.floating_ip_pools.list()
+
+ return (columns,
+ (utils.get_item_properties(
+ s, columns,
+ ) for s in data))
+
+
+class ListIPFloatingPool(ListFloatingIPPool):
+ """List pools of floating IP addresses"""
+
+ # TODO(tangchen): Remove this class and ``ip floating pool list`` command
+ # two cycles after Mitaka.
+
+ # This notifies cliff to not display the help for this command
+ deprecated = True
+
+ log = logging.getLogger('deprecated')
+
+ def take_action_network(self, client, parsed_args):
+ self.log.warning(_('This command has been deprecated. '
+ 'Please use "floating ip pool list" instead.'))
+ return super(ListIPFloatingPool, self).take_action_network(
+ client, parsed_args)
+
+ def take_action_compute(self, client, parsed_args):
+ self.log.warning(_('This command has been deprecated. '
+ 'Please use "floating ip pool list" instead.'))
+ return super(ListIPFloatingPool, self).take_action_compute(
+ client, parsed_args)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 5d1431b5..05c5a012 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -14,6 +14,7 @@
"""Port action implementations"""
import argparse
+import copy
import json
import logging
@@ -196,7 +197,8 @@ def _add_updatable_args(parser):
parser.add_argument(
'--device-owner',
metavar='<device-owner>',
- help=_("Device owner of this port")
+ help=_("Device owner of this port. This is the entity that uses "
+ "the port (for example, network:dhcp).")
)
parser.add_argument(
'--vnic-type',
@@ -337,6 +339,13 @@ class ListPort(command.Lister):
def get_parser(self, prog_name):
parser = super(ListPort, self).get_parser(prog_name)
parser.add_argument(
+ '--device-owner',
+ metavar='<device-owner>',
+ help=_("List only ports with the specified device owner. "
+ "This is the entity that uses the port (for example, "
+ "network:dhcp).")
+ )
+ parser.add_argument(
'--router',
metavar='<router>',
dest='router',
@@ -361,10 +370,12 @@ class ListPort(command.Lister):
)
filters = {}
+ if parsed_args.device_owner is not None:
+ filters['device_owner'] = parsed_args.device_owner
if parsed_args.router:
_router = client.find_router(parsed_args.router,
ignore_missing=False)
- filters = {'device_id': _router.id}
+ filters['device_id'] = _router.id
data = client.ports(**filters)
@@ -475,3 +486,61 @@ class ShowPort(command.ShowOne):
columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (columns, data)
+
+
+class UnsetPort(command.Command):
+ """Unset port properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetPort, self).get_parser(prog_name)
+ parser.add_argument(
+ '--fixed-ip',
+ metavar='subnet=<subnet>,ip-address=<ip-address>',
+ action=parseractions.MultiKeyValueAction,
+ optional_keys=['subnet', 'ip-address'],
+ help=_("Desired IP and/or subnet (name or ID) which should be "
+ "removed from this port: subnet=<subnet>,"
+ "ip-address=<ip-address> (repeat option to unset multiple "
+ "fixed IP addresses)"))
+
+ parser.add_argument(
+ '--binding-profile',
+ metavar='<binding-profile-key>',
+ action='append',
+ help=_("Desired key which should be removed from binding:profile"
+ "(repeat option to unset multiple binding:profile data)"))
+ parser.add_argument(
+ 'port',
+ metavar="<port>",
+ help=_("Port to modify (name or ID)")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_port(parsed_args.port, ignore_missing=False)
+ # SDK ignores update() if it recieves a modified obj and attrs
+ # To handle the same tmp_obj is created in all take_action of
+ # Unset* classes
+ tmp_fixed_ips = copy.deepcopy(obj.fixed_ips)
+ tmp_binding_profile = copy.deepcopy(obj.binding_profile)
+ _prepare_fixed_ips(self.app.client_manager, parsed_args)
+ attrs = {}
+ if parsed_args.fixed_ip:
+ try:
+ for ip in parsed_args.fixed_ip:
+ tmp_fixed_ips.remove(ip)
+ except ValueError:
+ msg = _("Port does not contain fixed-ip %s") % ip
+ raise exceptions.CommandError(msg)
+ attrs['fixed_ips'] = tmp_fixed_ips
+ if parsed_args.binding_profile:
+ try:
+ for key in parsed_args.binding_profile:
+ del tmp_binding_profile[key]
+ except KeyError:
+ msg = _("Port does not contain binding-profile %s") % key
+ raise exceptions.CommandError(msg)
+ attrs['binding:profile'] = tmp_binding_profile
+ if attrs:
+ client.update_port(obj, **attrs)
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index b076d82e..f26f6804 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -28,6 +28,11 @@ from openstackclient.identity import common as identity_common
LOG = logging.getLogger(__name__)
+def _update_arguments(obj_list, parsed_args_list):
+ for item in parsed_args_list:
+ obj_list.remove(item)
+
+
def _format_allocation_pools(data):
pool_formatted = ['%s-%s' % (pool.get('start', ''), pool.get('end', ''))
for pool in data]
@@ -163,7 +168,7 @@ def _get_attrs(client_manager, parsed_args, is_create=True):
attrs['allocation_pools'] = parsed_args.allocation_pools
if parsed_args.dhcp:
attrs['enable_dhcp'] = True
- elif parsed_args.no_dhcp:
+ if parsed_args.no_dhcp:
attrs['enable_dhcp'] = False
if ('dns_nameservers' in parsed_args and
parsed_args.dns_nameservers is not None):
@@ -218,7 +223,6 @@ class CreateSubnet(command.ShowOne):
dhcp_enable_group.add_argument(
'--dhcp',
action='store_true',
- default=True,
help=_("Enable DHCP (default)")
)
dhcp_enable_group.add_argument(
@@ -433,3 +437,81 @@ class ShowSubnet(command.ShowOne):
columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (columns, data)
+
+
+class UnsetSubnet(command.Command):
+ """Unset subnet properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetSubnet, self).get_parser(prog_name)
+ parser.add_argument(
+ '--allocation-pool',
+ metavar='start=<ip-address>,end=<ip-address>',
+ dest='allocation_pools',
+ action=parseractions.MultiKeyValueAction,
+ required_keys=['start', 'end'],
+ help=_('Allocation pool to be removed from this subnet '
+ 'e.g.: start=192.168.199.2,end=192.168.199.254 '
+ '(repeat option to unset multiple Allocation pools)')
+ )
+ parser.add_argument(
+ '--dns-nameserver',
+ metavar='<dns-nameserver>',
+ action='append',
+ dest='dns_nameservers',
+ help=_('DNS server to be removed from this subnet '
+ '(repeat option to set multiple DNS servers)')
+ )
+ parser.add_argument(
+ '--host-route',
+ metavar='destination=<subnet>,gateway=<ip-address>',
+ dest='host_routes',
+ action=parseractions.MultiKeyValueAction,
+ required_keys=['destination', 'gateway'],
+ help=_('Route to be removed from this subnet '
+ 'e.g.: destination=10.10.0.0/16,gateway=192.168.71.254 '
+ 'destination: destination subnet (in CIDR notation) '
+ 'gateway: nexthop IP address '
+ '(repeat option to unset multiple host routes)')
+ )
+ parser.add_argument(
+ 'subnet',
+ metavar="<subnet>",
+ help=_("Subnet to modify (name or ID)")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_subnet(parsed_args.subnet, ignore_missing=False)
+ tmp_obj = copy.deepcopy(obj)
+ attrs = {}
+ if parsed_args.dns_nameservers:
+ try:
+ _update_arguments(tmp_obj.dns_nameservers,
+ parsed_args.dns_nameservers)
+ except ValueError as error:
+ msg = (_("%s not in dns-nameservers") % str(error))
+ raise exceptions.CommandError(msg)
+ attrs['dns_nameservers'] = tmp_obj.dns_nameservers
+ if parsed_args.host_routes:
+ try:
+ _update_arguments(
+ tmp_obj.host_routes,
+ convert_entries_to_nexthop(parsed_args.host_routes))
+ except ValueError as error:
+ msg = (_("Subnet does not have %s in host-routes") %
+ str(error))
+ raise exceptions.CommandError(msg)
+ attrs['host_routes'] = tmp_obj.host_routes
+ if parsed_args.allocation_pools:
+ try:
+ _update_arguments(tmp_obj.allocation_pools,
+ parsed_args.allocation_pools)
+ except ValueError as error:
+ msg = (_("Subnet does not have %s in allocation-pools") %
+ str(error))
+ raise exceptions.CommandError(msg)
+ attrs['allocation_pools'] = tmp_obj.allocation_pools
+ if attrs:
+ client.update_subnet(obj, **attrs)
diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py
index 55dfed83..ed2bb0ef 100644
--- a/openstackclient/network/v2/subnet_pool.py
+++ b/openstackclient/network/v2/subnet_pool.py
@@ -12,6 +12,7 @@
#
"""Subnet pool action implementations"""
+import copy
import logging
@@ -337,3 +338,43 @@ class ShowSubnetPool(command.ShowOne):
columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (columns, data)
+
+
+class UnsetSubnetPool(command.Command):
+ """Unset subnet pool properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetSubnetPool, self).get_parser(prog_name)
+ parser.add_argument(
+ '--pool-prefix',
+ metavar='<pool-prefix>',
+ action='append',
+ dest='prefixes',
+ help=_('Remove subnet pool prefixes (in CIDR notation). '
+ '(repeat option to unset multiple prefixes).'),
+ )
+ parser.add_argument(
+ 'subnet_pool',
+ metavar="<subnet-pool>",
+ help=_("Subnet pool to modify (name or ID)")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_subnet_pool(
+ parsed_args.subnet_pool, ignore_missing=False)
+ tmp_prefixes = copy.deepcopy(obj.prefixes)
+ attrs = {}
+ if parsed_args.prefixes:
+ for prefix in parsed_args.prefixes:
+ try:
+ tmp_prefixes.remove(prefix)
+ except ValueError:
+ msg = _(
+ "Subnet pool does not "
+ "contain prefix %s") % prefix
+ raise exceptions.CommandError(msg)
+ attrs['prefixes'] = tmp_prefixes
+ if attrs:
+ client.update_subnet_pool(obj, **attrs)
diff --git a/openstackclient/shell.py b/openstackclient/shell.py
index 49a06040..ed729e53 100644..100755
--- a/openstackclient/shell.py
+++ b/openstackclient/shell.py
@@ -331,10 +331,10 @@ class OpenStackShell(app.App):
'auth_type': auth_type,
},
)
- except (IOError, OSError) as e:
+ except (IOError, OSError):
self.log.critical("Could not read clouds.yaml configuration file")
self.print_help_if_requested()
- raise e
+ raise
# TODO(thowe): Change cliff so the default value for debug
# can be set to None.
diff --git a/openstackclient/tests/common/test_clientmanager.py b/openstackclient/tests/common/test_clientmanager.py
index 0a9965e0..117c7184 100644
--- a/openstackclient/tests/common/test_clientmanager.py
+++ b/openstackclient/tests/common/test_clientmanager.py
@@ -19,10 +19,10 @@ import mock
from keystoneauth1.access import service_catalog
from keystoneauth1.identity import v2 as auth_v2
from keystoneauth1 import token_endpoint
+from osc_lib.api import auth
from osc_lib import exceptions as exc
from requests_mock.contrib import fixture
-from openstackclient.api import auth
from openstackclient.common import clientmanager
from openstackclient.tests import fakes
from openstackclient.tests import utils
@@ -356,7 +356,7 @@ class TestClientManager(utils.TestCase):
client_manager.setup_auth,
)
- @mock.patch('openstackclient.api.auth.check_valid_authentication_options')
+ @mock.patch('osc_lib.api.auth.check_valid_authentication_options')
def test_client_manager_auth_setup_once(self, check_authn_options_func):
client_manager = clientmanager.ClientManager(
cli_options=FakeOptions(
diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py
index 882d8480..76402476 100644
--- a/openstackclient/tests/compute/v2/fakes.py
+++ b/openstackclient/tests/compute/v2/fakes.py
@@ -81,7 +81,10 @@ class FakeAggregate(object):
"availability_zone": "ag_zone",
}
}
+
+ # Overwrite default attributes.
aggregate_info.update(attrs)
+
aggregate = fakes.FakeResource(
info=copy.deepcopy(aggregate_info),
loaded=True)
@@ -178,6 +181,9 @@ class FakeComputev2Client(object):
self.floating_ips = mock.Mock()
self.floating_ips.resource_class = fakes.FakeResource(None, {})
+ self.floating_ip_pools = mock.Mock()
+ self.floating_ip_pools.resource_class = fakes.FakeResource(None, {})
+
self.networks = mock.Mock()
self.networks.resource_class = fakes.FakeResource(None, {})
@@ -251,6 +257,8 @@ class FakeAgent(object):
'md5hash': 'agent-md5hash',
'hypervisor': 'hypervisor',
}
+
+ # Overwrite default attributes.
agent_info.update(attrs)
agent = fakes.FakeResource(info=copy.deepcopy(agent_info),
@@ -390,7 +398,7 @@ class FakeHypervisorStats(object):
:param Dictionary attrs:
A dictionary with all attributes
:return:
- A FakeResource object, with id, hypervisor_hostname, and so on
+ A FakeResource object, with count, current_workload, and so on
"""
attrs = attrs or {}
@@ -409,6 +417,8 @@ class FakeHypervisorStats(object):
'vcpus': 8,
'vcpus_used': 3,
}
+
+ # Overwrite default attributes.
stats_info.update(attrs)
# Set default method.
@@ -572,7 +582,7 @@ class FakeServer(object):
:param Dictionary methods:
A dictionary with all methods
:return:
- A FakeResource object, with id, name, metadata
+ A FakeResource object, with id, name, metadata, and so on
"""
attrs = attrs or {}
methods = methods or {}
@@ -648,7 +658,7 @@ class FakeService(object):
:param Dictionary attrs:
A dictionary with all attributes
:return:
- A FakeResource object, with id, host, binary
+ A FakeResource object, with id, host, binary, and so on
"""
attrs = attrs or {}
@@ -700,7 +710,7 @@ class FakeFlavor(object):
:param Dictionary attrs:
A dictionary with all attributes
:return:
- A FakeResource object, with id, name, ram, vcpus, properties
+ A FakeResource object, with id, name, ram, vcpus, and so on
"""
attrs = attrs or {}
@@ -716,6 +726,7 @@ class FakeFlavor(object):
'OS-FLV-DISABLED:disabled': False,
'os-flavor-access:is_public': True,
'OS-FLV-EXT-DATA:ephemeral': 0,
+ 'properties': {'property': 'value'},
}
# Overwrite default attributes.
@@ -786,7 +797,7 @@ class FakeKeypair(object):
:param Dictionary attrs:
A dictionary with all attributes
:return:
- A FakeResource
+ A FakeResource object, name, fingerprint, and so on
"""
attrs = attrs or {}
@@ -970,6 +981,54 @@ class FakeFloatingIP(object):
return mock.MagicMock(side_effect=floating_ips)
+class FakeFloatingIPPool(object):
+ """Fake one or more floating ip pools."""
+
+ @staticmethod
+ def create_one_floating_ip_pool(attrs=None):
+ """Create a fake floating ip pool.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with name, etc
+ """
+ if attrs is None:
+ attrs = {}
+
+ # Set default attributes.
+ floating_ip_pool_attrs = {
+ 'name': 'floating-ip-pool-name-' + uuid.uuid4().hex,
+ }
+
+ # Overwrite default attributes.
+ floating_ip_pool_attrs.update(attrs)
+
+ floating_ip_pool = fakes.FakeResource(
+ info=copy.deepcopy(floating_ip_pool_attrs),
+ loaded=True)
+
+ return floating_ip_pool
+
+ @staticmethod
+ def create_floating_ip_pools(attrs=None, count=2):
+ """Create multiple fake floating ip pools.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of floating ip pools to fake
+ :return:
+ A list of FakeResource objects faking the floating ip pools
+ """
+ floating_ip_pools = []
+ for i in range(0, count):
+ floating_ip_pools.append(
+ FakeFloatingIPPool.create_one_floating_ip_pool(attrs)
+ )
+ return floating_ip_pools
+
+
class FakeNetwork(object):
"""Fake one or more networks."""
@@ -1075,7 +1134,7 @@ class FakeHost(object):
:param Dictionary attrs:
A dictionary with all attributes
:return:
- A FakeResource object, with id and other attributes
+ A FakeResource object, with uuid and other attributes
"""
attrs = attrs or {}
@@ -1131,6 +1190,7 @@ class FakeServerGroup(object):
if attrs is None:
attrs = {}
+ # Set default attributes.
server_group_info = {
'id': 'server-group-id-' + uuid.uuid4().hex,
'members': [],
@@ -1140,7 +1200,10 @@ class FakeServerGroup(object):
'project_id': 'server-group-project-id-' + uuid.uuid4().hex,
'user_id': 'server-group-user-id-' + uuid.uuid4().hex,
}
+
+ # Overwrite default attributes.
server_group_info.update(attrs)
+
server_group = fakes.FakeResource(
info=copy.deepcopy(server_group_info),
loaded=True)
diff --git a/openstackclient/tests/compute/v2/test_agent.py b/openstackclient/tests/compute/v2/test_agent.py
index da329728..7695ee41 100644
--- a/openstackclient/tests/compute/v2/test_agent.py
+++ b/openstackclient/tests/compute/v2/test_agent.py
@@ -25,7 +25,9 @@ from openstackclient.tests import utils as tests_utils
class TestAgent(compute_fakes.TestComputev2):
- fake_agent = compute_fakes.FakeAgent.create_one_agent()
+ attr = {}
+ attr['agent_id'] = 1
+ fake_agent = compute_fakes.FakeAgent.create_one_agent(attr)
columns = (
'agent_id',
@@ -238,21 +240,34 @@ class TestAgentSet(TestAgent):
super(TestAgentSet, self).setUp()
self.agents_mock.update.return_value = self.fake_agent
+ self.agents_mock.list.return_value = [self.fake_agent]
self.cmd = agent.SetAgent(self.app, None)
- def test_agent_set(self):
+ def test_agent_set_nothing(self):
arglist = [
- 'id',
- 'new-version',
- 'new-url',
- 'new-md5hash',
+ '1',
+ ]
+ verifylist = [
+ ('id', '1'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ self.fake_agent.version,
+ self.fake_agent.url,
+ self.fake_agent.md5hash)
+ self.assertIsNone(result)
+
+ def test_agent_set_version(self):
+ arglist = [
+ '1',
+ '--agent-version', 'new-version',
]
verifylist = [
- ('id', 'id'),
+ ('id', '1'),
('version', 'new-version'),
- ('url', 'new-url'),
- ('md5hash', 'new-md5hash'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -260,6 +275,46 @@ class TestAgentSet(TestAgent):
self.agents_mock.update.assert_called_with(parsed_args.id,
parsed_args.version,
+ self.fake_agent.url,
+ self.fake_agent.md5hash)
+ self.assertIsNone(result)
+
+ def test_agent_set_url(self):
+ arglist = [
+ '1',
+ '--url', 'new-url',
+ ]
+
+ verifylist = [
+ ('id', '1'),
+ ('url', 'new-url'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ self.fake_agent.version,
parsed_args.url,
+ self.fake_agent.md5hash)
+ self.assertIsNone(result)
+
+ def test_agent_set_md5hash(self):
+ arglist = [
+ '1',
+ '--md5hash', 'new-md5hash',
+ ]
+
+ verifylist = [
+ ('id', '1'),
+ ('md5hash', 'new-md5hash'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ self.fake_agent.version,
+ self.fake_agent.url,
parsed_args.md5hash)
self.assertIsNone(result)
diff --git a/openstackclient/tests/compute/v2/test_flavor.py b/openstackclient/tests/compute/v2/test_flavor.py
index da76b6d7..20ae8706 100644
--- a/openstackclient/tests/compute/v2/test_flavor.py
+++ b/openstackclient/tests/compute/v2/test_flavor.py
@@ -56,6 +56,7 @@ class TestFlavorCreate(TestFlavor):
'id',
'name',
'os-flavor-access:is_public',
+ 'properties',
'ram',
'rxtx_factor',
'swap',
@@ -68,6 +69,7 @@ class TestFlavorCreate(TestFlavor):
flavor.id,
flavor.name,
flavor.is_public,
+ utils.format_dict(flavor.properties),
flavor.ram,
flavor.rxtx_factor,
flavor.swap,
@@ -116,7 +118,6 @@ class TestFlavorCreate(TestFlavor):
def test_flavor_create_all_options(self):
arglist = [
- self.flavor.name,
'--id', self.flavor.id,
'--ram', str(self.flavor.ram),
'--disk', str(self.flavor.disk),
@@ -125,9 +126,10 @@ class TestFlavorCreate(TestFlavor):
'--vcpus', str(self.flavor.vcpus),
'--rxtx-factor', str(self.flavor.rxtx_factor),
'--public',
+ '--property', 'property=value',
+ self.flavor.name,
]
verifylist = [
- ('name', self.flavor.name),
('id', self.flavor.id),
('ram', self.flavor.ram),
('disk', self.flavor.disk),
@@ -136,6 +138,8 @@ class TestFlavorCreate(TestFlavor):
('vcpus', self.flavor.vcpus),
('rxtx_factor', self.flavor.rxtx_factor),
('public', True),
+ ('property', {'property': 'value'}),
+ ('name', self.flavor.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -152,6 +156,8 @@ class TestFlavorCreate(TestFlavor):
)
columns, data = self.cmd.take_action(parsed_args)
self.flavors_mock.create.assert_called_once_with(*args)
+ self.flavor.set_keys.assert_called_once_with({'property': 'value'})
+ self.flavor.get_keys.assert_called_once_with()
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -160,7 +166,6 @@ class TestFlavorCreate(TestFlavor):
self.flavor.is_public = False
arglist = [
- self.flavor.name,
'--id', self.flavor.id,
'--ram', str(self.flavor.ram),
'--disk', str(self.flavor.disk),
@@ -170,9 +175,11 @@ class TestFlavorCreate(TestFlavor):
'--rxtx-factor', str(self.flavor.rxtx_factor),
'--private',
'--project', identity_fakes.project_id,
+ '--property', 'key1=value1',
+ '--property', 'key2=value2',
+ self.flavor.name,
]
verifylist = [
- ('name', self.flavor.name),
('id', self.flavor.id),
('ram', self.flavor.ram),
('disk', self.flavor.disk),
@@ -182,6 +189,8 @@ class TestFlavorCreate(TestFlavor):
('rxtx_factor', self.flavor.rxtx_factor),
('public', False),
('project', identity_fakes.project_id),
+ ('property', {'key1': 'value1', 'key2': 'value2'}),
+ ('name', self.flavor.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -202,6 +211,9 @@ class TestFlavorCreate(TestFlavor):
self.flavor.id,
identity_fakes.project_id,
)
+ self.flavor.set_keys.assert_called_with(
+ {'key1': 'value1', 'key2': 'value2'})
+ self.flavor.get_keys.assert_called_with()
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py
index 0f155601..1c5a5fe4 100644
--- a/openstackclient/tests/compute/v2/test_server.py
+++ b/openstackclient/tests/compute/v2/test_server.py
@@ -43,6 +43,11 @@ class TestServer(compute_fakes.TestComputev2):
self.flavors_mock = self.app.client_manager.compute.flavors
self.flavors_mock.reset_mock()
+ # Get a shortcut to the compute client SecurityGroupManager Mock
+ self.security_groups_mock = \
+ self.app.client_manager.compute.security_groups
+ self.security_groups_mock.reset_mock()
+
# Get a shortcut to the image client ImageManager Mock
self.images_mock = self.app.client_manager.image.images
self.images_mock.reset_mock()
@@ -51,10 +56,10 @@ class TestServer(compute_fakes.TestComputev2):
self.volumes_mock = self.app.client_manager.volume.volumes
self.volumes_mock.reset_mock()
- # Set object attributes to be tested. Could be overwriten in subclass.
+ # Set object attributes to be tested. Could be overwritten in subclass.
self.attrs = {}
- # Set object methods to be tested. Could be overwriten in subclass.
+ # Set object methods to be tested. Could be overwritten in subclass.
self.methods = {}
def setup_servers_mock(self, count):
@@ -88,6 +93,80 @@ class TestServer(compute_fakes.TestComputev2):
self.assertIsNone(result)
+class TestServerAddFixedIP(TestServer):
+
+ def setUp(self):
+ super(TestServerAddFixedIP, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.networks_mock = self.app.client_manager.compute.networks
+
+ # Get the command object to test
+ self.cmd = server.AddFixedIP(self.app, None)
+
+ # Set add_fixed_ip method to be tested.
+ self.methods = {
+ 'add_fixed_ip': None,
+ }
+
+ def test_server_add_fixed_ip(self):
+ servers = self.setup_servers_mock(count=1)
+ network = compute_fakes.FakeNetwork.create_one_network()
+ self.networks_mock.get.return_value = network
+
+ arglist = [
+ servers[0].id,
+ network.id,
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('network', network.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].add_fixed_ip.assert_called_once_with(
+ network.id,
+ )
+ self.assertIsNone(result)
+
+
+class TestServerAddFloatingIP(TestServer):
+
+ def setUp(self):
+ super(TestServerAddFloatingIP, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.networks_mock = self.app.client_manager.compute.networks
+
+ # Get the command object to test
+ self.cmd = server.AddFloatingIP(self.app, None)
+
+ # Set add_floating_ip method to be tested.
+ self.methods = {
+ 'add_floating_ip': None,
+ }
+
+ def test_server_add_floating_ip(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ '1.2.3.4',
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('ip_address', '1.2.3.4'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].add_floating_ip.assert_called_once_with('1.2.3.4')
+ self.assertIsNone(result)
+
+
class TestServerCreate(TestServer):
columns = (
@@ -843,6 +922,118 @@ class TestServerRebuild(TestServer):
self.server.rebuild.assert_called_with(self.image, None)
+class TestServerRemoveFixedIP(TestServer):
+
+ def setUp(self):
+ super(TestServerRemoveFixedIP, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.RemoveFixedIP(self.app, None)
+
+ # Set unshelve method to be tested.
+ self.methods = {
+ 'remove_fixed_ip': None,
+ }
+
+ def test_server_remove_fixed_ip(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ '1.2.3.4',
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('ip_address', '1.2.3.4'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].remove_fixed_ip.assert_called_once_with('1.2.3.4')
+ self.assertIsNone(result)
+
+
+class TestServerRemoveFloatingIP(TestServer):
+
+ def setUp(self):
+ super(TestServerRemoveFloatingIP, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server.RemoveFloatingIP(self.app, None)
+
+ # Set unshelve method to be tested.
+ self.methods = {
+ 'remove_floating_ip': None,
+ }
+
+ def test_server_remove_floating_ip(self):
+ servers = self.setup_servers_mock(count=1)
+
+ arglist = [
+ servers[0].id,
+ '1.2.3.4',
+ ]
+ verifylist = [
+ ('server', servers[0].id),
+ ('ip_address', '1.2.3.4'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ servers[0].remove_floating_ip.assert_called_once_with('1.2.3.4')
+ self.assertIsNone(result)
+
+
+class TestServerRemoveSecurityGroup(TestServer):
+
+ def setUp(self):
+ super(TestServerRemoveSecurityGroup, self).setUp()
+
+ self.security_group = \
+ compute_fakes.FakeSecurityGroup.create_one_security_group()
+ # This is the return value for utils.find_resource() for security group
+ self.security_groups_mock.get.return_value = self.security_group
+
+ attrs = {
+ 'security_groups': [{'name': self.security_group.id}]
+ }
+ methods = {
+ 'remove_security_group': None,
+ }
+
+ self.server = compute_fakes.FakeServer.create_one_server(
+ attrs=attrs,
+ methods=methods
+ )
+ # This is the return value for utils.find_resource() for server
+ self.servers_mock.get.return_value = self.server
+
+ # Get the command object to test
+ self.cmd = server.RemoveServerSecurityGroup(self.app, None)
+
+ def test_server_remove_security_group(self):
+ arglist = [
+ self.server.id,
+ self.security_group.id
+ ]
+ verifylist = [
+ ('server', self.server.id),
+ ('group', self.security_group.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.security_groups_mock.get.assert_called_with(
+ self.security_group.id,
+ )
+ self.servers_mock.get.assert_called_with(self.server.id)
+ self.server.remove_security_group.assert_called_with(
+ self.security_group.id,
+ )
+ self.assertIsNone(result)
+
+
class TestServerResize(TestServer):
def setUp(self):
diff --git a/openstackclient/tests/compute/v2/test_server_backup.py b/openstackclient/tests/compute/v2/test_server_backup.py
index b6802ff0..8eeb0dca 100644
--- a/openstackclient/tests/compute/v2/test_server_backup.py
+++ b/openstackclient/tests/compute/v2/test_server_backup.py
@@ -34,10 +34,10 @@ class TestServerBackup(compute_fakes.TestComputev2):
self.images_mock = self.app.client_manager.image.images
self.images_mock.reset_mock()
- # Set object attributes to be tested. Could be overwriten in subclass.
+ # Set object attributes to be tested. Could be overwritten in subclass.
self.attrs = {}
- # Set object methods to be tested. Could be overwriten in subclass.
+ # Set object methods to be tested. Could be overwritten in subclass.
self.methods = {}
def setup_servers_mock(self, count):
diff --git a/openstackclient/tests/compute/v2/test_server_image.py b/openstackclient/tests/compute/v2/test_server_image.py
index 8a8bd9bc..c3c52da0 100644
--- a/openstackclient/tests/compute/v2/test_server_image.py
+++ b/openstackclient/tests/compute/v2/test_server_image.py
@@ -33,10 +33,10 @@ class TestServerImage(compute_fakes.TestComputev2):
self.images_mock = self.app.client_manager.image.images
self.images_mock.reset_mock()
- # Set object attributes to be tested. Could be overwriten in subclass.
+ # Set object attributes to be tested. Could be overwritten in subclass.
self.attrs = {}
- # Set object methods to be tested. Could be overwriten in subclass.
+ # Set object methods to be tested. Could be overwritten in subclass.
self.methods = {}
def setup_servers_mock(self, count):
diff --git a/openstackclient/tests/identity/v3/fakes.py b/openstackclient/tests/identity/v3/fakes.py
index dd918616..df532df4 100644
--- a/openstackclient/tests/identity/v3/fakes.py
+++ b/openstackclient/tests/identity/v3/fakes.py
@@ -15,6 +15,7 @@
import copy
import mock
+import uuid
from keystoneauth1 import access
from keystoneauth1 import fixture
@@ -575,3 +576,66 @@ class TestOAuth1(utils.TestCommand):
endpoint=fakes.AUTH_URL,
token=fakes.AUTH_TOKEN
)
+
+
+class FakeProject(object):
+ """Fake one or more project."""
+
+ @staticmethod
+ def create_one_project(attrs=None):
+ """Create a fake project.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ project_info = {
+ 'id': 'project-id-' + uuid.uuid4().hex,
+ 'name': 'project-name-' + uuid.uuid4().hex,
+ 'description': 'project-description-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'is_domain': False,
+ 'domain_id': 'domain-id-' + uuid.uuid4().hex,
+ 'parent_id': 'parent-id-' + uuid.uuid4().hex,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ project_info.update(attrs)
+
+ project = fakes.FakeResource(info=copy.deepcopy(project_info),
+ loaded=True)
+ return project
+
+
+class FakeDomain(object):
+ """Fake one or more domain."""
+
+ @staticmethod
+ def create_one_domain(attrs=None):
+ """Create a fake domain.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with id, name, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ domain_info = {
+ 'id': 'domain-id-' + uuid.uuid4().hex,
+ 'name': 'domain-name-' + uuid.uuid4().hex,
+ 'description': 'domain-description-' + uuid.uuid4().hex,
+ 'enabled': True,
+ 'links': 'links-' + uuid.uuid4().hex,
+ }
+ domain_info.update(attrs)
+
+ domain = fakes.FakeResource(info=copy.deepcopy(domain_info),
+ loaded=True)
+ return domain
diff --git a/openstackclient/tests/identity/v3/test_consumer.py b/openstackclient/tests/identity/v3/test_consumer.py
index 4a8cf087..d90c7347 100644
--- a/openstackclient/tests/identity/v3/test_consumer.py
+++ b/openstackclient/tests/identity/v3/test_consumer.py
@@ -83,7 +83,7 @@ class TestConsumerDelete(TestOAuth1):
identity_fakes.consumer_id,
]
verifylist = [
- ('consumer', identity_fakes.consumer_id),
+ ('consumer', [identity_fakes.consumer_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_domain.py b/openstackclient/tests/identity/v3/test_domain.py
index e06e0681..5e094021 100644
--- a/openstackclient/tests/identity/v3/test_domain.py
+++ b/openstackclient/tests/identity/v3/test_domain.py
@@ -10,10 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import copy
-
from openstackclient.identity.v3 import domain
-from openstackclient.tests import fakes
from openstackclient.tests.identity.v3 import fakes as identity_fakes
@@ -35,20 +32,17 @@ class TestDomainCreate(TestDomain):
'id',
'name',
)
- datalist = (
- identity_fakes.domain_description,
- True,
- identity_fakes.domain_id,
- identity_fakes.domain_name,
- )
def setUp(self):
super(TestDomainCreate, self).setUp()
- self.domains_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
+ self.domain = identity_fakes.FakeDomain.create_one_domain()
+ self.domains_mock.create.return_value = self.domain
+ self.datalist = (
+ self.domain.description,
+ True,
+ self.domain.id,
+ self.domain.name,
)
# Get the command object to test
@@ -56,10 +50,10 @@ class TestDomainCreate(TestDomain):
def test_domain_create_no_options(self):
arglist = [
- identity_fakes.domain_name,
+ self.domain.name,
]
verifylist = [
- ('name', identity_fakes.domain_name),
+ ('name', self.domain.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -70,7 +64,7 @@ class TestDomainCreate(TestDomain):
# Set expected values
kwargs = {
- 'name': identity_fakes.domain_name,
+ 'name': self.domain.name,
'description': None,
'enabled': True,
}
@@ -84,11 +78,11 @@ class TestDomainCreate(TestDomain):
def test_domain_create_description(self):
arglist = [
'--description', 'new desc',
- identity_fakes.domain_name,
+ self.domain.name,
]
verifylist = [
('description', 'new desc'),
- ('name', identity_fakes.domain_name),
+ ('name', self.domain.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -99,7 +93,7 @@ class TestDomainCreate(TestDomain):
# Set expected values
kwargs = {
- 'name': identity_fakes.domain_name,
+ 'name': self.domain.name,
'description': 'new desc',
'enabled': True,
}
@@ -113,11 +107,11 @@ class TestDomainCreate(TestDomain):
def test_domain_create_enable(self):
arglist = [
'--enable',
- identity_fakes.domain_name,
+ self.domain.name,
]
verifylist = [
('enable', True),
- ('name', identity_fakes.domain_name),
+ ('name', self.domain.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -128,7 +122,7 @@ class TestDomainCreate(TestDomain):
# Set expected values
kwargs = {
- 'name': identity_fakes.domain_name,
+ 'name': self.domain.name,
'description': None,
'enabled': True,
}
@@ -142,11 +136,11 @@ class TestDomainCreate(TestDomain):
def test_domain_create_disable(self):
arglist = [
'--disable',
- identity_fakes.domain_name,
+ self.domain.name,
]
verifylist = [
('disable', True),
- ('name', identity_fakes.domain_name),
+ ('name', self.domain.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -157,7 +151,7 @@ class TestDomainCreate(TestDomain):
# Set expected values
kwargs = {
- 'name': identity_fakes.domain_name,
+ 'name': self.domain.name,
'description': None,
'enabled': False,
}
@@ -171,15 +165,13 @@ class TestDomainCreate(TestDomain):
class TestDomainDelete(TestDomain):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
def setUp(self):
super(TestDomainDelete, self).setUp()
# This is the return value for utils.find_resource()
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
self.domains_mock.delete.return_value = None
# Get the command object to test
@@ -187,33 +179,29 @@ class TestDomainDelete(TestDomain):
def test_domain_delete(self):
arglist = [
- identity_fakes.domain_id,
+ self.domain.id,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', [self.domain.id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.domains_mock.delete.assert_called_with(
- identity_fakes.domain_id,
+ self.domain.id,
)
self.assertIsNone(result)
class TestDomainList(TestDomain):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
def setUp(self):
super(TestDomainList, self).setUp()
- self.domains_mock.list.return_value = [
- fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- ),
- ]
+ self.domains_mock.list.return_value = [self.domain]
# Get the command object to test
self.cmd = domain.ListDomain(self.app, None)
@@ -232,56 +220,54 @@ class TestDomainList(TestDomain):
collist = ('ID', 'Name', 'Enabled', 'Description')
self.assertEqual(collist, columns)
datalist = ((
- identity_fakes.domain_id,
- identity_fakes.domain_name,
+ self.domain.id,
+ self.domain.name,
True,
- identity_fakes.domain_description,
+ self.domain.description,
), )
self.assertEqual(datalist, tuple(data))
class TestDomainSet(TestDomain):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
def setUp(self):
super(TestDomainSet, self).setUp()
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
- self.domains_mock.update.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.update.return_value = self.domain
# Get the command object to test
self.cmd = domain.SetDomain(self.app, None)
def test_domain_set_no_options(self):
arglist = [
- identity_fakes.domain_name,
+ self.domain.name,
]
verifylist = [
- ('domain', identity_fakes.domain_name),
+ ('domain', self.domain.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.assertNotCalled(self.domains_mock.update)
+ kwargs = {}
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
self.assertIsNone(result)
def test_domain_set_name(self):
arglist = [
'--name', 'qwerty',
- identity_fakes.domain_id,
+ self.domain.id,
]
verifylist = [
('name', 'qwerty'),
- ('domain', identity_fakes.domain_id),
+ ('domain', self.domain.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -292,7 +278,7 @@ class TestDomainSet(TestDomain):
'name': 'qwerty',
}
self.domains_mock.update.assert_called_with(
- identity_fakes.domain_id,
+ self.domain.id,
**kwargs
)
self.assertIsNone(result)
@@ -300,11 +286,11 @@ class TestDomainSet(TestDomain):
def test_domain_set_description(self):
arglist = [
'--description', 'new desc',
- identity_fakes.domain_id,
+ self.domain.id,
]
verifylist = [
('description', 'new desc'),
- ('domain', identity_fakes.domain_id),
+ ('domain', self.domain.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -315,7 +301,7 @@ class TestDomainSet(TestDomain):
'description': 'new desc',
}
self.domains_mock.update.assert_called_with(
- identity_fakes.domain_id,
+ self.domain.id,
**kwargs
)
self.assertIsNone(result)
@@ -323,11 +309,11 @@ class TestDomainSet(TestDomain):
def test_domain_set_enable(self):
arglist = [
'--enable',
- identity_fakes.domain_id,
+ self.domain.id,
]
verifylist = [
('enable', True),
- ('domain', identity_fakes.domain_id),
+ ('domain', self.domain.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -338,7 +324,7 @@ class TestDomainSet(TestDomain):
'enabled': True,
}
self.domains_mock.update.assert_called_with(
- identity_fakes.domain_id,
+ self.domain.id,
**kwargs
)
self.assertIsNone(result)
@@ -346,11 +332,11 @@ class TestDomainSet(TestDomain):
def test_domain_set_disable(self):
arglist = [
'--disable',
- identity_fakes.domain_id,
+ self.domain.id,
]
verifylist = [
('disable', True),
- ('domain', identity_fakes.domain_id),
+ ('domain', self.domain.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -361,7 +347,7 @@ class TestDomainSet(TestDomain):
'enabled': False,
}
self.domains_mock.update.assert_called_with(
- identity_fakes.domain_id,
+ self.domain.id,
**kwargs
)
self.assertIsNone(result)
@@ -372,21 +358,17 @@ class TestDomainShow(TestDomain):
def setUp(self):
super(TestDomainShow, self).setUp()
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
-
+ self.domain = identity_fakes.FakeDomain.create_one_domain()
+ self.domains_mock.get.return_value = self.domain
# Get the command object to test
self.cmd = domain.ShowDomain(self.app, None)
def test_domain_show(self):
arglist = [
- identity_fakes.domain_id,
+ self.domain.id,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.domain.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.app.client_manager.identity.tokens.get_token_data.return_value = \
@@ -405,15 +387,15 @@ class TestDomainShow(TestDomain):
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
self.domains_mock.get.assert_called_with(
- identity_fakes.domain_id,
+ self.domain.id,
)
collist = ('description', 'enabled', 'id', 'name')
self.assertEqual(collist, columns)
datalist = (
- identity_fakes.domain_description,
+ self.domain.description,
True,
- identity_fakes.domain_id,
- identity_fakes.domain_name,
+ self.domain.id,
+ self.domain.name,
)
self.assertEqual(datalist, data)
diff --git a/openstackclient/tests/identity/v3/test_endpoint.py b/openstackclient/tests/identity/v3/test_endpoint.py
index d953459c..04276319 100644
--- a/openstackclient/tests/identity/v3/test_endpoint.py
+++ b/openstackclient/tests/identity/v3/test_endpoint.py
@@ -273,7 +273,7 @@ class TestEndpointDelete(TestEndpoint):
identity_fakes.endpoint_id,
]
verifylist = [
- ('endpoint', identity_fakes.endpoint_id),
+ ('endpoint', [identity_fakes.endpoint_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -485,7 +485,17 @@ class TestEndpointSet(TestEndpoint):
result = self.cmd.take_action(parsed_args)
- self.assertNotCalled(self.endpoints_mock.update)
+ kwargs = {
+ 'enabled': None,
+ 'interface': None,
+ 'region': None,
+ 'service': None,
+ 'url': None,
+ }
+ self.endpoints_mock.update.assert_called_with(
+ identity_fakes.endpoint_id,
+ **kwargs
+ )
self.assertIsNone(result)
def test_endpoint_set_interface(self):
diff --git a/openstackclient/tests/identity/v3/test_identity_provider.py b/openstackclient/tests/identity/v3/test_identity_provider.py
index 3ff79812..1ec61052 100644
--- a/openstackclient/tests/identity/v3/test_identity_provider.py
+++ b/openstackclient/tests/identity/v3/test_identity_provider.py
@@ -255,7 +255,7 @@ class TestIdentityProviderDelete(TestIdentityProvider):
identity_fakes.idp_id,
]
verifylist = [
- ('identity_provider', identity_fakes.idp_id),
+ ('identity_provider', [identity_fakes.idp_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -585,8 +585,8 @@ class TestIdentityProviderSet(TestIdentityProvider):
# expect take_action() to return (None, None) as
# neither --enable nor --disable was specified
- self.assertIsNone(columns)
- self.assertIsNone(data)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
class TestIdentityProviderShow(TestIdentityProvider):
@@ -599,7 +599,11 @@ class TestIdentityProviderShow(TestIdentityProvider):
copy.deepcopy(identity_fakes.IDENTITY_PROVIDER),
loaded=True,
)
+
+ self.identity_providers_mock.get.side_effect = [Exception("Not found"),
+ ret]
self.identity_providers_mock.get.return_value = ret
+
# Get the command object to test
self.cmd = identity_provider.ShowIdentityProvider(self.app, None)
diff --git a/openstackclient/tests/identity/v3/test_mappings.py b/openstackclient/tests/identity/v3/test_mappings.py
index af7b135d..6aa1a6e5 100644
--- a/openstackclient/tests/identity/v3/test_mappings.py
+++ b/openstackclient/tests/identity/v3/test_mappings.py
@@ -91,7 +91,7 @@ class TestMappingDelete(TestMapping):
identity_fakes.mapping_id
]
verifylist = [
- ('mapping', identity_fakes.mapping_id)
+ ('mapping', [identity_fakes.mapping_id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_project.py b/openstackclient/tests/identity/v3/test_project.py
index 93bf18af..65874baa 100644
--- a/openstackclient/tests/identity/v3/test_project.py
+++ b/openstackclient/tests/identity/v3/test_project.py
@@ -13,13 +13,11 @@
# under the License.
#
-import copy
import mock
from osc_lib import exceptions
from openstackclient.identity.v3 import project
-from openstackclient.tests import fakes
from openstackclient.tests.identity.v3 import fakes as identity_fakes
@@ -39,48 +37,46 @@ class TestProject(identity_fakes.TestIdentityv3):
class TestProjectCreate(TestProject):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
columns = (
'description',
'domain_id',
'enabled',
'id',
- 'name'
- )
- datalist = (
- identity_fakes.project_description,
- identity_fakes.domain_id,
- True,
- identity_fakes.project_id,
- identity_fakes.project_name,
+ 'is_domain',
+ 'name',
+ 'parent_id',
)
def setUp(self):
super(TestProjectCreate, self).setUp()
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
-
- self.projects_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': self.domain.id})
+ self.domains_mock.get.return_value = self.domain
+ self.projects_mock.create.return_value = self.project
+ self.datalist = (
+ self.project.description,
+ self.project.domain_id,
+ True,
+ self.project.id,
+ False,
+ self.project.name,
+ self.project.parent_id,
)
-
# Get the command object to test
self.cmd = project.CreateProject(self.app, None)
def test_project_create_no_options(self):
arglist = [
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
('parent', None),
('enable', False),
('disable', False),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -91,7 +87,7 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
+ 'name': self.project.name,
'domain': None,
'description': None,
'enabled': True,
@@ -103,27 +99,37 @@ class TestProjectCreate(TestProject):
**kwargs
)
- collist = ('description', 'domain_id', 'enabled', 'id', 'name')
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ )
self.assertEqual(collist, columns)
datalist = (
- identity_fakes.project_description,
- identity_fakes.domain_id,
+ self.project.description,
+ self.project.domain_id,
True,
- identity_fakes.project_id,
- identity_fakes.project_name,
+ self.project.id,
+ False,
+ self.project.name,
+ self.project.parent_id,
)
self.assertEqual(datalist, data)
def test_project_create_description(self):
arglist = [
'--description', 'new desc',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
('description', 'new desc'),
('enable', False),
('disable', False),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
('parent', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -135,7 +141,7 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
+ 'name': self.project.name,
'domain': None,
'description': 'new desc',
'enabled': True,
@@ -152,14 +158,14 @@ class TestProjectCreate(TestProject):
def test_project_create_domain(self):
arglist = [
- '--domain', identity_fakes.domain_name,
- identity_fakes.project_name,
+ '--domain', self.project.domain_id,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_name),
+ ('domain', self.project.domain_id),
('enable', False),
('disable', False),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
('parent', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -171,8 +177,8 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
- 'domain': identity_fakes.domain_id,
+ 'name': self.project.name,
+ 'domain': self.project.domain_id,
'description': None,
'enabled': True,
'parent': None,
@@ -188,14 +194,14 @@ class TestProjectCreate(TestProject):
def test_project_create_domain_no_perms(self):
arglist = [
- '--domain', identity_fakes.domain_id,
- identity_fakes.project_name,
+ '--domain', self.project.domain_id,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
('enable', False),
('disable', False),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
('parent', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -207,8 +213,8 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
- 'domain': identity_fakes.domain_id,
+ 'name': self.project.name,
+ 'domain': self.project.domain_id,
'description': None,
'enabled': True,
'parent': None,
@@ -222,12 +228,12 @@ class TestProjectCreate(TestProject):
def test_project_create_enable(self):
arglist = [
'--enable',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
('enable', True),
('disable', False),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
('parent', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -239,7 +245,7 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
+ 'name': self.project.name,
'domain': None,
'description': None,
'enabled': True,
@@ -257,12 +263,12 @@ class TestProjectCreate(TestProject):
def test_project_create_disable(self):
arglist = [
'--disable',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
('enable', False),
('disable', True),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
('parent', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -274,7 +280,7 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
+ 'name': self.project.name,
'domain': None,
'description': None,
'enabled': False,
@@ -293,11 +299,11 @@ class TestProjectCreate(TestProject):
arglist = [
'--property', 'fee=fi',
'--property', 'fo=fum',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
('property', {'fee': 'fi', 'fo': 'fum'}),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -308,7 +314,7 @@ class TestProjectCreate(TestProject):
# Set expected values
kwargs = {
- 'name': identity_fakes.project_name,
+ 'name': self.project.name,
'domain': None,
'description': None,
'enabled': True,
@@ -326,37 +332,32 @@ class TestProjectCreate(TestProject):
self.assertEqual(self.datalist, data)
def test_project_create_parent(self):
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
- self.projects_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT_WITH_PARENT),
- loaded=True,
- )
+ self.parent = identity_fakes.FakeProject.create_one_project()
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': self.domain.id, 'parent_id': self.parent.id})
+ self.projects_mock.get.return_value = self.parent
+ self.projects_mock.create.return_value = self.project
arglist = [
- '--domain', identity_fakes.PROJECT_WITH_PARENT['domain_id'],
- '--parent', identity_fakes.PROJECT['name'],
- identity_fakes.PROJECT_WITH_PARENT['name'],
+ '--domain', self.project.domain_id,
+ '--parent', self.parent.name,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.PROJECT_WITH_PARENT['domain_id']),
- ('parent', identity_fakes.PROJECT['name']),
+ ('domain', self.project.domain_id),
+ ('parent', self.parent.name),
('enable', False),
('disable', False),
- ('name', identity_fakes.PROJECT_WITH_PARENT['name']),
+ ('name', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
kwargs = {
- 'name': identity_fakes.PROJECT_WITH_PARENT['name'],
- 'domain': identity_fakes.PROJECT_WITH_PARENT['domain_id'],
- 'parent': identity_fakes.PROJECT['id'],
+ 'name': self.project.name,
+ 'domain': self.project.domain_id,
+ 'parent': self.parent.id,
'description': None,
'enabled': True,
}
@@ -370,17 +371,19 @@ class TestProjectCreate(TestProject):
'domain_id',
'enabled',
'id',
+ 'is_domain',
'name',
'parent_id',
)
self.assertEqual(columns, collist)
datalist = (
- identity_fakes.PROJECT_WITH_PARENT['description'],
- identity_fakes.PROJECT_WITH_PARENT['domain_id'],
- identity_fakes.PROJECT_WITH_PARENT['enabled'],
- identity_fakes.PROJECT_WITH_PARENT['id'],
- identity_fakes.PROJECT_WITH_PARENT['name'],
- identity_fakes.PROJECT['id'],
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.parent.id,
)
self.assertEqual(data, datalist)
@@ -392,16 +395,16 @@ class TestProjectCreate(TestProject):
'Invalid parent')
arglist = [
- '--domain', identity_fakes.domain_name,
+ '--domain', self.project.domain_id,
'--parent', 'invalid',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_name),
+ ('domain', self.project.domain_id),
('parent', 'invalid'),
('enable', False),
('disable', False),
- ('name', identity_fakes.project_name),
+ ('name', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -414,15 +417,13 @@ class TestProjectCreate(TestProject):
class TestProjectDelete(TestProject):
+ project = identity_fakes.FakeProject.create_one_project()
+
def setUp(self):
super(TestProjectDelete, self).setUp()
# This is the return value for utils.find_resource()
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
self.projects_mock.delete.return_value = None
# Get the command object to test
@@ -430,44 +431,42 @@ class TestProjectDelete(TestProject):
def test_project_delete_no_options(self):
arglist = [
- identity_fakes.project_id,
+ self.project.id,
]
verifylist = [
- ('projects', [identity_fakes.project_id]),
+ ('projects', [self.project.id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.projects_mock.delete.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
)
self.assertIsNone(result)
class TestProjectList(TestProject):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': domain.id})
+
columns = (
'ID',
'Name',
)
datalist = (
(
- identity_fakes.project_id,
- identity_fakes.project_name,
+ project.id,
+ project.name,
),
)
def setUp(self):
super(TestProjectList, self).setUp()
- self.projects_mock.list.return_value = [
- fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- ),
- ]
+ self.projects_mock.list.return_value = [self.project]
# Get the command object to test
self.cmd = project.ListProject(self.app, None)
@@ -504,27 +503,23 @@ class TestProjectList(TestProject):
collist = ('ID', 'Name', 'Domain ID', 'Description', 'Enabled')
self.assertEqual(collist, columns)
datalist = ((
- identity_fakes.project_id,
- identity_fakes.project_name,
- identity_fakes.domain_id,
- identity_fakes.project_description,
+ self.project.id,
+ self.project.name,
+ self.project.domain_id,
+ self.project.description,
True,
), )
self.assertEqual(datalist, tuple(data))
def test_project_list_domain(self):
arglist = [
- '--domain', identity_fakes.domain_name,
+ '--domain', self.project.domain_id,
]
verifylist = [
- ('domain', identity_fakes.domain_name),
+ ('domain', self.project.domain_id),
]
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -533,17 +528,17 @@ class TestProjectList(TestProject):
# containing the data to be listed.
columns, data = self.cmd.take_action(parsed_args)
self.projects_mock.list.assert_called_with(
- domain=identity_fakes.domain_id)
+ domain=self.project.domain_id)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_project_list_domain_no_perms(self):
arglist = [
- '--domain', identity_fakes.domain_id,
+ '--domain', self.project.domain_id,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
mocker = mock.Mock()
@@ -553,42 +548,34 @@ class TestProjectList(TestProject):
columns, data = self.cmd.take_action(parsed_args)
self.projects_mock.list.assert_called_with(
- domain=identity_fakes.domain_id)
+ domain=self.project.domain_id)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestProjectSet(TestProject):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+ project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': domain.id})
+
def setUp(self):
super(TestProjectSet, self).setUp()
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
- self.projects_mock.update.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
+ self.projects_mock.update.return_value = self.project
# Get the command object to test
self.cmd = project.SetProject(self.app, None)
def test_project_set_no_options(self):
arglist = [
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
- ('project', identity_fakes.project_name),
+ ('project', self.project.name),
('enable', False),
('disable', False),
]
@@ -601,15 +588,15 @@ class TestProjectSet(TestProject):
def test_project_set_name(self):
arglist = [
'--name', 'qwerty',
- '--domain', identity_fakes.domain_id,
- identity_fakes.project_name,
+ '--domain', self.project.domain_id,
+ self.project.name,
]
verifylist = [
('name', 'qwerty'),
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
('enable', False),
('disable', False),
- ('project', identity_fakes.project_name),
+ ('project', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -622,23 +609,23 @@ class TestProjectSet(TestProject):
# ProjectManager.update(project, name=, domain=, description=,
# enabled=, **kwargs)
self.projects_mock.update.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
**kwargs
)
self.assertIsNone(result)
def test_project_set_description(self):
arglist = [
- '--domain', identity_fakes.domain_id,
+ '--domain', self.project.domain_id,
'--description', 'new desc',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
('description', 'new desc'),
('enable', False),
('disable', False),
- ('project', identity_fakes.project_name),
+ ('project', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -649,22 +636,22 @@ class TestProjectSet(TestProject):
'description': 'new desc',
}
self.projects_mock.update.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
**kwargs
)
self.assertIsNone(result)
def test_project_set_enable(self):
arglist = [
- '--domain', identity_fakes.domain_id,
+ '--domain', self.project.domain_id,
'--enable',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
('enable', True),
('disable', False),
- ('project', identity_fakes.project_name),
+ ('project', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -675,22 +662,22 @@ class TestProjectSet(TestProject):
'enabled': True,
}
self.projects_mock.update.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
**kwargs
)
self.assertIsNone(result)
def test_project_set_disable(self):
arglist = [
- '--domain', identity_fakes.domain_id,
+ '--domain', self.project.domain_id,
'--disable',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
('enable', False),
('disable', True),
- ('project', identity_fakes.project_name),
+ ('project', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -701,22 +688,22 @@ class TestProjectSet(TestProject):
'enabled': False,
}
self.projects_mock.update.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
**kwargs
)
self.assertIsNone(result)
def test_project_set_property(self):
arglist = [
- '--domain', identity_fakes.domain_id,
+ '--domain', self.project.domain_id,
'--property', 'fee=fi',
'--property', 'fo=fum',
- identity_fakes.project_name,
+ self.project.name,
]
verifylist = [
- ('domain', identity_fakes.domain_id),
+ ('domain', self.project.domain_id),
('property', {'fee': 'fi', 'fo': 'fum'}),
- ('project', identity_fakes.project_name),
+ ('project', self.project.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -728,7 +715,7 @@ class TestProjectSet(TestProject):
'fo': 'fum',
}
self.projects_mock.update.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
**kwargs
)
self.assertIsNone(result)
@@ -736,25 +723,28 @@ class TestProjectSet(TestProject):
class TestProjectShow(TestProject):
+ domain = identity_fakes.FakeDomain.create_one_domain()
+
def setUp(self):
super(TestProjectShow, self).setUp()
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={'domain_id': self.domain.id})
# Get the command object to test
self.cmd = project.ShowProject(self.app, None)
def test_project_show(self):
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
+
arglist = [
- identity_fakes.project_id,
+ self.project.id,
]
verifylist = [
- ('project', identity_fakes.project_id),
+ ('project', self.project.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -772,38 +762,51 @@ class TestProjectShow(TestProject):
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
+
self.projects_mock.get.assert_called_with(
- identity_fakes.project_id,
+ self.project.id,
parents_as_list=False,
subtree_as_list=False,
)
- collist = ('description', 'domain_id', 'enabled', 'id', 'name')
+ collist = (
+ 'description',
+ 'domain_id',
+ 'enabled',
+ 'id',
+ 'is_domain',
+ 'name',
+ 'parent_id',
+ )
self.assertEqual(collist, columns)
datalist = (
- identity_fakes.project_description,
- identity_fakes.domain_id,
+ self.project.description,
+ self.project.domain_id,
True,
- identity_fakes.project_id,
- identity_fakes.project_name,
+ self.project.id,
+ False,
+ self.project.name,
+ self.project.parent_id,
)
self.assertEqual(datalist, data)
def test_project_show_parents(self):
- project = copy.deepcopy(identity_fakes.PROJECT_WITH_GRANDPARENT)
- project['parents'] = identity_fakes.grandparents
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- project,
- loaded=True,
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={
+ 'parent_id': self.project.parent_id,
+ 'parents': [{'project': {'id': self.project.parent_id}}]
+ }
)
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
arglist = [
- identity_fakes.PROJECT_WITH_GRANDPARENT['id'],
+ self.project.id,
'--parents',
]
verifylist = [
- ('project', identity_fakes.PROJECT_WITH_GRANDPARENT['id']),
+ ('project', self.project.id),
('parents', True),
('children', False),
]
@@ -820,7 +823,7 @@ class TestProjectShow(TestProject):
columns, data = self.cmd.take_action(parsed_args)
self.projects_mock.get.assert_called_with(
- identity_fakes.PROJECT_WITH_GRANDPARENT['id'],
+ self.project.id,
parents_as_list=True,
subtree_as_list=False,
)
@@ -830,37 +833,41 @@ class TestProjectShow(TestProject):
'domain_id',
'enabled',
'id',
+ 'is_domain',
'name',
'parent_id',
'parents',
)
self.assertEqual(columns, collist)
datalist = (
- identity_fakes.PROJECT_WITH_GRANDPARENT['description'],
- identity_fakes.PROJECT_WITH_GRANDPARENT['domain_id'],
- identity_fakes.PROJECT_WITH_GRANDPARENT['enabled'],
- identity_fakes.PROJECT_WITH_GRANDPARENT['id'],
- identity_fakes.PROJECT_WITH_GRANDPARENT['name'],
- identity_fakes.PROJECT_WITH_GRANDPARENT['parent_id'],
- identity_fakes.ids_for_parents_and_grandparents,
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.project.parent_id,
+ [self.project.parent_id],
)
self.assertEqual(data, datalist)
def test_project_show_subtree(self):
- project = copy.deepcopy(identity_fakes.PROJECT_WITH_PARENT)
- project['subtree'] = identity_fakes.children
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- project,
- loaded=True,
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={
+ 'parent_id': self.project.parent_id,
+ 'subtree': [{'project': {'id': 'children-id'}}]
+ }
)
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
arglist = [
- identity_fakes.PROJECT_WITH_PARENT['id'],
+ self.project.id,
'--children',
]
verifylist = [
- ('project', identity_fakes.PROJECT_WITH_PARENT['id']),
+ ('project', self.project.id),
('parents', False),
('children', True),
]
@@ -877,7 +884,7 @@ class TestProjectShow(TestProject):
columns, data = self.cmd.take_action(parsed_args)
self.projects_mock.get.assert_called_with(
- identity_fakes.PROJECT_WITH_PARENT['id'],
+ self.project.id,
parents_as_list=False,
subtree_as_list=True,
)
@@ -887,39 +894,43 @@ class TestProjectShow(TestProject):
'domain_id',
'enabled',
'id',
+ 'is_domain',
'name',
'parent_id',
'subtree',
)
self.assertEqual(columns, collist)
datalist = (
- identity_fakes.PROJECT_WITH_PARENT['description'],
- identity_fakes.PROJECT_WITH_PARENT['domain_id'],
- identity_fakes.PROJECT_WITH_PARENT['enabled'],
- identity_fakes.PROJECT_WITH_PARENT['id'],
- identity_fakes.PROJECT_WITH_PARENT['name'],
- identity_fakes.PROJECT_WITH_PARENT['parent_id'],
- identity_fakes.ids_for_children,
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.project.parent_id,
+ ['children-id'],
)
self.assertEqual(data, datalist)
def test_project_show_parents_and_children(self):
- project = copy.deepcopy(identity_fakes.PROJECT_WITH_PARENT)
- project['subtree'] = identity_fakes.children
- project['parents'] = identity_fakes.parents
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- project,
- loaded=True,
+ self.project = identity_fakes.FakeProject.create_one_project(
+ attrs={
+ 'parent_id': self.project.parent_id,
+ 'parents': [{'project': {'id': self.project.parent_id}}],
+ 'subtree': [{'project': {'id': 'children-id'}}]
+ }
)
+ self.projects_mock.get.side_effect = [Exception("Not found"),
+ self.project]
+ self.projects_mock.get.return_value = self.project
arglist = [
- identity_fakes.PROJECT_WITH_PARENT['id'],
+ self.project.id,
'--parents',
'--children',
]
verifylist = [
- ('project', identity_fakes.PROJECT_WITH_PARENT['id']),
+ ('project', self.project.id),
('parents', True),
('children', True),
]
@@ -936,7 +947,7 @@ class TestProjectShow(TestProject):
columns, data = self.cmd.take_action(parsed_args)
self.projects_mock.get.assert_called_with(
- identity_fakes.PROJECT_WITH_PARENT['id'],
+ self.project.id,
parents_as_list=True,
subtree_as_list=True,
)
@@ -946,6 +957,7 @@ class TestProjectShow(TestProject):
'domain_id',
'enabled',
'id',
+ 'is_domain',
'name',
'parent_id',
'parents',
@@ -953,13 +965,14 @@ class TestProjectShow(TestProject):
)
self.assertEqual(columns, collist)
datalist = (
- identity_fakes.PROJECT_WITH_PARENT['description'],
- identity_fakes.PROJECT_WITH_PARENT['domain_id'],
- identity_fakes.PROJECT_WITH_PARENT['enabled'],
- identity_fakes.PROJECT_WITH_PARENT['id'],
- identity_fakes.PROJECT_WITH_PARENT['name'],
- identity_fakes.PROJECT_WITH_PARENT['parent_id'],
- identity_fakes.ids_for_parents,
- identity_fakes.ids_for_children,
+ self.project.description,
+ self.project.domain_id,
+ self.project.enabled,
+ self.project.id,
+ self.project.is_domain,
+ self.project.name,
+ self.project.parent_id,
+ [self.project.parent_id],
+ ['children-id'],
)
self.assertEqual(data, datalist)
diff --git a/openstackclient/tests/identity/v3/test_protocol.py b/openstackclient/tests/identity/v3/test_protocol.py
index 238b0ff8..f718b27b 100644
--- a/openstackclient/tests/identity/v3/test_protocol.py
+++ b/openstackclient/tests/identity/v3/test_protocol.py
@@ -88,7 +88,7 @@ class TestProtocolDelete(TestProtocol):
identity_fakes.protocol_id
]
verifylist = [
- ('federation_protocol', identity_fakes.protocol_id),
+ ('federation_protocol', [identity_fakes.protocol_id]),
('identity_provider', identity_fakes.idp_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_region.py b/openstackclient/tests/identity/v3/test_region.py
index 02dec568..41ee5ce9 100644
--- a/openstackclient/tests/identity/v3/test_region.py
+++ b/openstackclient/tests/identity/v3/test_region.py
@@ -153,7 +153,7 @@ class TestRegionDelete(TestRegion):
identity_fakes.region_id,
]
verifylist = [
- ('region', identity_fakes.region_id),
+ ('region', [identity_fakes.region_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -253,7 +253,11 @@ class TestRegionSet(TestRegion):
result = self.cmd.take_action(parsed_args)
- self.assertNotCalled(self.regions_mock.update)
+ kwargs = {}
+ self.regions_mock.update.assert_called_with(
+ identity_fakes.region_id,
+ **kwargs
+ )
self.assertIsNone(result)
def test_region_set_description(self):
diff --git a/openstackclient/tests/identity/v3/test_service.py b/openstackclient/tests/identity/v3/test_service.py
index 1e70383f..a1f85adc 100644
--- a/openstackclient/tests/identity/v3/test_service.py
+++ b/openstackclient/tests/identity/v3/test_service.py
@@ -200,7 +200,7 @@ class TestServiceDelete(TestService):
identity_fakes.service_name,
]
verifylist = [
- ('service', identity_fakes.service_name),
+ ('service', [identity_fakes.service_name]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/identity/v3/test_service_provider.py b/openstackclient/tests/identity/v3/test_service_provider.py
index 99ea1f75..f5270d83 100644
--- a/openstackclient/tests/identity/v3/test_service_provider.py
+++ b/openstackclient/tests/identity/v3/test_service_provider.py
@@ -185,7 +185,7 @@ class TestServiceProviderDelete(TestServiceProvider):
service_fakes.sp_id,
]
verifylist = [
- ('service_provider', service_fakes.sp_id),
+ ('service_provider', [service_fakes.sp_id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -377,8 +377,15 @@ class TestServiceProviderSet(TestServiceProvider):
# expect take_action() to return (None, None) as none of --disabled,
# --enabled, --description, --service-provider-url, --auth_url option
# was set.
- self.assertIsNone(columns)
- self.assertIsNone(data)
+ self.assertEqual(self.columns, columns)
+ datalist = (
+ service_fakes.sp_auth_url,
+ service_fakes.sp_description,
+ True,
+ service_fakes.sp_id,
+ service_fakes.service_provider_url
+ )
+ self.assertEqual(datalist, data)
class TestServiceProviderShow(TestServiceProvider):
@@ -391,7 +398,10 @@ class TestServiceProviderShow(TestServiceProvider):
copy.deepcopy(service_fakes.SERVICE_PROVIDER),
loaded=True,
)
+ self.service_providers_mock.get.side_effect = [Exception("Not found"),
+ ret]
self.service_providers_mock.get.return_value = ret
+
# Get the command object to test
self.cmd = service_provider.ShowServiceProvider(self.app, None)
diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py
index 14aa331f..cf08d138 100644
--- a/openstackclient/tests/image/v1/test_image.py
+++ b/openstackclient/tests/image/v1/test_image.py
@@ -363,6 +363,7 @@ class TestImageList(TestImage):
'Disk Format',
'Container Format',
'Size',
+ 'Checksum',
'Status',
'Visibility',
'Protected',
@@ -378,6 +379,7 @@ class TestImageList(TestImage):
'',
'',
'',
+ '',
'public',
False,
image_fakes.image_owner,
diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py
index 8e22fbb2..d450dec1 100644
--- a/openstackclient/tests/image/v2/fakes.py
+++ b/openstackclient/tests/image/v2/fakes.py
@@ -49,13 +49,6 @@ IMAGE_SHOW = copy.copy(IMAGE)
IMAGE_SHOW['tags'] = ''
IMAGE_SHOW_data = tuple((IMAGE_SHOW[x] for x in sorted(IMAGE_SHOW)))
-member_status = 'pending'
-MEMBER = {
- 'member_id': identity_fakes.project_id,
- 'image_id': image_id,
- 'status': member_status,
-}
-
# Just enough v2 schema to do some testing
IMAGE_schema = {
"additionalProperties": {
@@ -190,7 +183,7 @@ class FakeImage(object):
:param Dictionary attrs:
A dictionary with all attrbutes of image
- :retrun:
+ :return:
A FakeResource object with id, name, owner, protected,
visibility and tags attrs
"""
@@ -288,3 +281,29 @@ class FakeImage(object):
else:
data_list.append(getattr(image, x))
return tuple(data_list)
+
+ @staticmethod
+ def create_one_image_member(attrs=None):
+ """Create a fake image member.
+
+ :param Dictionary attrs:
+ A dictionary with all attrbutes of image member
+ :return:
+ A FakeResource object with member_id, image_id and so on
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ image_member_info = {
+ 'member_id': 'member-id-' + uuid.uuid4().hex,
+ 'image_id': 'image-id-' + uuid.uuid4().hex,
+ 'status': 'pending',
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ image_member_info.update(attrs)
+
+ image_member = fakes.FakeModel(
+ copy.deepcopy(image_member_info))
+
+ return image_member
diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py
index 592def21..c6b83bc5 100644
--- a/openstackclient/tests/image/v2/test_image.py
+++ b/openstackclient/tests/image/v2/test_image.py
@@ -347,6 +347,10 @@ class TestImageCreate(TestImage):
class TestAddProjectToImage(TestImage):
_image = image_fakes.FakeImage.create_one_image()
+ new_member = image_fakes.FakeImage.create_one_image_member(
+ attrs={'image_id': _image.id,
+ 'member_id': identity_fakes.project_id}
+ )
columns = (
'image_id',
@@ -357,7 +361,7 @@ class TestAddProjectToImage(TestImage):
datalist = (
_image.id,
identity_fakes.project_id,
- image_fakes.member_status
+ new_member.status
)
def setUp(self):
@@ -367,11 +371,7 @@ class TestAddProjectToImage(TestImage):
self.images_mock.get.return_value = self._image
# Update the image_id in the MEMBER dict
- self.new_member = copy.deepcopy(image_fakes.MEMBER)
- self.new_member['image_id'] = self._image.id
- self.image_members_mock.create.return_value = fakes.FakeModel(
- self.new_member,
- )
+ self.image_members_mock.create.return_value = self.new_member
self.project_mock.get.return_value = fakes.FakeResource(
None,
copy.deepcopy(identity_fakes.PROJECT),
@@ -643,6 +643,7 @@ class TestImageList(TestImage):
'Disk Format',
'Container Format',
'Size',
+ 'Checksum',
'Status',
'Visibility',
'Protected',
@@ -658,6 +659,7 @@ class TestImageList(TestImage):
'',
'',
'',
+ '',
self._image.visibility,
self._image.protected,
self._image.owner,
diff --git a/openstackclient/tests/network/v2/test_address_scope.py b/openstackclient/tests/network/v2/test_address_scope.py
index 722371f9..16e74f46 100644
--- a/openstackclient/tests/network/v2/test_address_scope.py
+++ b/openstackclient/tests/network/v2/test_address_scope.py
@@ -11,7 +11,6 @@
# under the License.
#
-import copy
import mock
from mock import call
@@ -35,11 +34,13 @@ class TestAddressScope(network_fakes.TestNetworkV2):
class TestCreateAddressScope(TestAddressScope):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
# The new address scope created.
new_address_scope = (
network_fakes.FakeAddressScope.create_one_address_scope(
attrs={
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': project.id,
}
))
columns = (
@@ -75,19 +76,11 @@ class TestCreateAddressScope(TestAddressScope):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# Get a shortcut to the DomainManager Mock
self.domains_mock = self.identity.domains
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
def test_create_no_options(self):
arglist = []
@@ -121,15 +114,15 @@ class TestCreateAddressScope(TestAddressScope):
arglist = [
'--ip-version', str(self.new_address_scope.ip_version),
'--share',
- '--project', identity_fakes_v3.project_name,
- '--project-domain', identity_fakes_v3.domain_name,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
self.new_address_scope.name,
]
verifylist = [
('ip_version', self.new_address_scope.ip_version),
('share', True),
- ('project', identity_fakes_v3.project_name),
- ('project_domain', identity_fakes_v3.domain_name),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
('name', self.new_address_scope.name),
]
@@ -139,7 +132,7 @@ class TestCreateAddressScope(TestAddressScope):
self.network.create_address_scope.assert_called_once_with(**{
'ip_version': self.new_address_scope.ip_version,
'shared': True,
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': self.project.id,
'name': self.new_address_scope.name,
})
self.assertEqual(self.columns, columns)
diff --git a/openstackclient/tests/network/v2/test_floating_ip.py b/openstackclient/tests/network/v2/test_floating_ip.py
index 5cd5279a..234fe446 100644
--- a/openstackclient/tests/network/v2/test_floating_ip.py
+++ b/openstackclient/tests/network/v2/test_floating_ip.py
@@ -211,7 +211,7 @@ class TestDeleteFloatingIPNetwork(TestFloatingIPNetwork):
self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.')
except exceptions.CommandError as e:
- self.assertEqual('1 of 2 floating_ip failed to delete.', str(e))
+ self.assertEqual('1 of 2 floating_ips failed to delete.', str(e))
self.network.find_ip.assert_any_call(
self.floating_ips[0].id, ignore_missing=False)
@@ -462,7 +462,7 @@ class TestDeleteFloatingIPCompute(TestFloatingIPCompute):
self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.')
except exceptions.CommandError as e:
- self.assertEqual('1 of 2 floating_ip failed to delete.', str(e))
+ self.assertEqual('1 of 2 floating_ips failed to delete.', str(e))
self.compute.floating_ips.get.assert_any_call(
self.floating_ips[0].id)
diff --git a/openstackclient/tests/network/v2/test_floating_ip_pool.py b/openstackclient/tests/network/v2/test_floating_ip_pool.py
new file mode 100644
index 00000000..22d20d20
--- /dev/null
+++ b/openstackclient/tests/network/v2/test_floating_ip_pool.py
@@ -0,0 +1,97 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+from osc_lib import exceptions
+
+from openstackclient.network.v2 import floating_ip_pool
+from openstackclient.tests.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.network.v2 import fakes as network_fakes
+
+
+# Tests for Network API v2
+#
+class TestFloatingIPPoolNetwork(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestFloatingIPPoolNetwork, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestListFloatingIPPoolNetwork(TestFloatingIPPoolNetwork):
+
+ def setUp(self):
+ super(TestListFloatingIPPoolNetwork, self).setUp()
+
+ # Get the command object to test
+ self.cmd = floating_ip_pool.ListFloatingIPPool(self.app,
+ self.namespace)
+
+ def test_floating_ip_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+
+# Tests for Compute network
+#
+class TestFloatingIPPoolCompute(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestFloatingIPPoolCompute, self).setUp()
+
+ # Get a shortcut to the compute client
+ self.compute = self.app.client_manager.compute
+
+
+class TestListFloatingIPPoolCompute(TestFloatingIPPoolCompute):
+
+ # The floating ip pools to list up
+ floating_ip_pools = \
+ compute_fakes.FakeFloatingIPPool.create_floating_ip_pools(count=3)
+
+ columns = (
+ 'Name',
+ )
+
+ data = []
+ for pool in floating_ip_pools:
+ data.append((
+ pool.name,
+ ))
+
+ def setUp(self):
+ super(TestListFloatingIPPoolCompute, self).setUp()
+
+ self.app.client_manager.network_endpoint_enabled = False
+
+ self.compute.floating_ip_pools.list.return_value = \
+ self.floating_ip_pools
+
+ # Get the command object to test
+ self.cmd = floating_ip_pool.ListFloatingIPPool(self.app, None)
+
+ def test_floating_ip_list(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute.floating_ip_pools.list.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
diff --git a/openstackclient/tests/network/v2/test_ip_availability.py b/openstackclient/tests/network/v2/test_ip_availability.py
index c6ec2b0b..21d44d07 100644
--- a/openstackclient/tests/network/v2/test_ip_availability.py
+++ b/openstackclient/tests/network/v2/test_ip_availability.py
@@ -11,7 +11,6 @@
# under the License.
#
-import copy
import mock
from osc_lib import utils as common_utils
@@ -41,11 +40,8 @@ class TestIPAvailability(network_fakes.TestNetworkV2):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
+ self.project = identity_fakes.FakeProject.create_one_project()
+ self.projects_mock.get.return_value = self.project
class TestListIPAvailability(TestIPAvailability):
@@ -109,16 +105,16 @@ class TestListIPAvailability(TestIPAvailability):
def test_list_project(self):
arglist = [
- '--project', identity_fakes.project_name
+ '--project', self.project.name
]
verifylist = [
- ('project', identity_fakes.project_name)
+ ('project', self.project.name)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- filters = {'tenant_id': identity_fakes.project_id,
+ filters = {'tenant_id': self.project.id,
'ip_version': 4}
self.network.network_ip_availabilities.assert_called_once_with(
diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py
index ffe6c973..aa016403 100644
--- a/openstackclient/tests/network/v2/test_network.py
+++ b/openstackclient/tests/network/v2/test_network.py
@@ -11,7 +11,6 @@
# under the License.
#
-import copy
import mock
from mock import call
@@ -40,10 +39,12 @@ class TestNetwork(network_fakes.TestNetworkV2):
class TestCreateNetworkIdentityV3(TestNetwork):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
# The new network created.
_network = network_fakes.FakeNetwork.create_one_network(
attrs={
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': project.id,
'availability_zone_hints': ["nova"],
}
)
@@ -98,19 +99,11 @@ class TestCreateNetworkIdentityV3(TestNetwork):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# Get a shortcut to the DomainManager Mock
self.domains_mock = self.identity.domains
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
def test_create_no_options(self):
arglist = []
@@ -145,8 +138,8 @@ class TestCreateNetworkIdentityV3(TestNetwork):
arglist = [
"--disable",
"--share",
- "--project", identity_fakes_v3.project_name,
- "--project-domain", identity_fakes_v3.domain_name,
+ "--project", self.project.name,
+ "--project-domain", self.domain.name,
"--availability-zone-hint", "nova",
"--external", "--default",
"--provider-network-type", "vlan",
@@ -159,8 +152,8 @@ class TestCreateNetworkIdentityV3(TestNetwork):
verifylist = [
('disable', True),
('share', True),
- ('project', identity_fakes_v3.project_name),
- ('project_domain', identity_fakes_v3.domain_name),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
('availability_zone_hints', ["nova"]),
('external', True),
('default', True),
@@ -180,7 +173,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
'availability_zone_hints': ["nova"],
'name': self._network.name,
'shared': True,
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': self.project.id,
'is_default': True,
'router:external': True,
'provider:network_type': 'vlan',
@@ -222,9 +215,10 @@ class TestCreateNetworkIdentityV3(TestNetwork):
class TestCreateNetworkIdentityV2(TestNetwork):
+ project = identity_fakes_v2.FakeProject.create_one_project()
# The new network created.
_network = network_fakes.FakeNetwork.create_one_network(
- attrs={'tenant_id': identity_fakes_v2.project_id}
+ attrs={'tenant_id': project.id}
)
columns = (
@@ -277,24 +271,20 @@ class TestCreateNetworkIdentityV2(TestNetwork):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.tenants
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v2.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# There is no DomainManager Mock in fake identity v2.
def test_create_with_project_identityv2(self):
arglist = [
- "--project", identity_fakes_v2.project_name,
+ "--project", self.project.name,
self._network.name,
]
verifylist = [
('enable', True),
('share', None),
('name', self._network.name),
- ('project', identity_fakes_v2.project_name),
+ ('project', self.project.name),
('external', False),
]
@@ -304,22 +294,22 @@ class TestCreateNetworkIdentityV2(TestNetwork):
self.network.create_network.assert_called_once_with(**{
'admin_state_up': True,
'name': self._network.name,
- 'tenant_id': identity_fakes_v2.project_id,
+ 'tenant_id': self.project.id,
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
def test_create_with_domain_identityv2(self):
arglist = [
- "--project", identity_fakes_v3.project_name,
- "--project-domain", identity_fakes_v3.domain_name,
+ "--project", self.project.name,
+ "--project-domain", "domain-name",
self._network.name,
]
verifylist = [
('enable', True),
('share', None),
- ('project', identity_fakes_v3.project_name),
- ('project_domain', identity_fakes_v3.domain_name),
+ ('project', self.project.name),
+ ('project_domain', "domain-name"),
('name', self._network.name),
('external', False),
]
diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py
index a998585e..a1cecec8 100644
--- a/openstackclient/tests/network/v2/test_port.py
+++ b/openstackclient/tests/network/v2/test_port.py
@@ -369,6 +369,47 @@ class TestListPort(TestPort):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
+ def test_port_list_device_owner_opt(self):
+ arglist = [
+ '--device-owner', self._ports[0].device_owner,
+ ]
+
+ verifylist = [
+ ('device_owner', self._ports[0].device_owner)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ports.assert_called_once_with(**{
+ 'device_owner': self._ports[0].device_owner
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_port_list_all_opt(self):
+ arglist = [
+ '--device-owner', self._ports[0].device_owner,
+ '--router', 'fake-router-name',
+ ]
+
+ verifylist = [
+ ('device_owner', self._ports[0].device_owner),
+ ('router', 'fake-router-name')
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.ports.assert_called_once_with(**{
+ 'device_owner': self._ports[0].device_owner,
+ 'device_id': 'fake-router-id'
+ })
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
class TestSetPort(TestPort):
@@ -575,3 +616,81 @@ class TestShowPort(TestPort):
ref_columns, ref_data = self._get_common_cols_data(self._port)
self.assertEqual(ref_columns, columns)
self.assertEqual(ref_data, data)
+
+
+class TestUnsetPort(TestPort):
+
+ def setUp(self):
+ super(TestUnsetPort, self).setUp()
+ self._testport = network_fakes.FakePort.create_one_port(
+ {'fixed_ips': [{'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '0.0.0.1'},
+ {'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '1.0.0.0'}],
+ 'binding:profile': {'batman': 'Joker', 'Superman': 'LexLuthor'}})
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'id': '042eb10a-3a18-4658-ab-cf47c8d03152'})
+ self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
+ self.network.find_port = mock.Mock(return_value=self._testport)
+ self.network.update_port = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = port.UnsetPort(self.app, self.namespace)
+
+ def test_unset_port_parameters(self):
+ arglist = [
+ '--fixed-ip',
+ 'subnet=042eb10a-3a18-4658-ab-cf47c8d03152,ip-address=1.0.0.0',
+ '--binding-profile', 'Superman',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{
+ 'subnet': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip-address': '1.0.0.0'}]),
+ ('binding_profile', ['Superman']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'fixed_ips': [{
+ 'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '0.0.0.1'}],
+ 'binding:profile': {'batman': 'Joker'}
+ }
+ self.network.update_port.assert_called_once_with(
+ self._testport, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_port_fixed_ip_not_existent(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=1.0.0.1',
+ '--binding-profile', 'Superman',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '1.0.0.1'}]),
+ ('binding_profile', ['Superman']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_unset_port_binding_profile_not_existent(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=1.0.0.0',
+ '--binding-profile', 'Neo',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '1.0.0.0'}]),
+ ('binding_profile', ['Neo']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/network/v2/test_security_group.py b/openstackclient/tests/network/v2/test_security_group.py
index b0c14985..cea64897 100644
--- a/openstackclient/tests/network/v2/test_security_group.py
+++ b/openstackclient/tests/network/v2/test_security_group.py
@@ -11,7 +11,6 @@
# under the License.
#
-import copy
import mock
from mock import call
@@ -45,6 +44,8 @@ class TestSecurityGroupCompute(compute_fakes.TestComputev2):
class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
# The security group to be created.
_security_group = \
network_fakes.FakeSecurityGroup.create_one_security_group()
@@ -81,19 +82,11 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# Get a shortcut to the DomainManager Mock
self.domains_mock = self.identity.domains
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
# Get the command object to test
self.cmd = security_group.CreateSecurityGroup(self.app, self.namespace)
@@ -123,15 +116,15 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
def test_create_all_options(self):
arglist = [
'--description', self._security_group.description,
- '--project', identity_fakes.project_name,
- '--project-domain', identity_fakes.domain_name,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
self._security_group.name,
]
verifylist = [
('description', self._security_group.description),
('name', self._security_group.name),
- ('project', identity_fakes.project_name),
- ('project_domain', identity_fakes.domain_name),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -140,7 +133,7 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
self.network.create_security_group.assert_called_once_with(**{
'description': self._security_group.description,
'name': self._security_group.name,
- 'tenant_id': identity_fakes.project_id,
+ 'tenant_id': self.project.id,
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -148,6 +141,8 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
class TestCreateSecurityGroupCompute(TestSecurityGroupCompute):
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
# The security group to be shown.
_security_group = \
compute_fakes.FakeSecurityGroup.create_one_security_group()
@@ -184,8 +179,8 @@ class TestCreateSecurityGroupCompute(TestSecurityGroupCompute):
def test_create_network_options(self):
arglist = [
- '--project', identity_fakes.project_name,
- '--project-domain', identity_fakes.domain_name,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
self._security_group.name,
]
self.assertRaises(tests_utils.ParserException,
@@ -301,7 +296,7 @@ class TestDeleteSecurityGroupNetwork(TestSecurityGroupNetwork):
self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.')
except exceptions.CommandError as e:
- self.assertEqual('1 of 2 group failed to delete.', str(e))
+ self.assertEqual('1 of 2 groups failed to delete.', str(e))
self.network.find_security_group.assert_any_call(
self._security_groups[0].name, ignore_missing=False)
@@ -389,7 +384,7 @@ class TestDeleteSecurityGroupCompute(TestSecurityGroupCompute):
self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.')
except exceptions.CommandError as e:
- self.assertEqual('1 of 2 group failed to delete.', str(e))
+ self.assertEqual('1 of 2 groups failed to delete.', str(e))
self.compute.security_groups.get.assert_any_call(
self._security_groups[0].id)
diff --git a/openstackclient/tests/network/v2/test_security_group_rule.py b/openstackclient/tests/network/v2/test_security_group_rule.py
index b2862679..34d35629 100644
--- a/openstackclient/tests/network/v2/test_security_group_rule.py
+++ b/openstackclient/tests/network/v2/test_security_group_rule.py
@@ -46,6 +46,8 @@ class TestSecurityGroupRuleCompute(compute_fakes.TestComputev2):
class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
# The security group rule to be created.
_security_group_rule = None
@@ -103,19 +105,11 @@ class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# Get a shortcut to the DomainManager Mock
self.domains_mock = self.identity.domains
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
# Get the command object to test
self.cmd = security_group_rule.CreateSecurityGroupRule(
@@ -306,8 +300,8 @@ class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
'--dst-port', str(self._security_group_rule.port_range_min),
'--egress',
'--ethertype', self._security_group_rule.ethertype,
- '--project', identity_fakes.project_name,
- '--project-domain', identity_fakes.domain_name,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
'--protocol', self._security_group_rule.protocol,
self._security_group.id,
]
@@ -316,8 +310,8 @@ class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
self._security_group_rule.port_range_max)),
('egress', True),
('ethertype', self._security_group_rule.ethertype),
- ('project', identity_fakes.project_name),
- ('project_domain', identity_fakes.domain_name),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
('protocol', self._security_group_rule.protocol),
('group', self._security_group.id),
]
@@ -332,7 +326,7 @@ class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
'port_range_min': self._security_group_rule.port_range_min,
'protocol': self._security_group_rule.protocol,
'security_group_id': self._security_group.id,
- 'tenant_id': identity_fakes.project_id,
+ 'tenant_id': self.project.id,
})
self.assertEqual(self.expected_columns, columns)
self.assertEqual(self.expected_data, data)
@@ -470,6 +464,8 @@ class TestCreateSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
class TestCreateSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
+ project = identity_fakes.FakeProject.create_one_project()
+ domain = identity_fakes.FakeDomain.create_one_domain()
# The security group rule to be created.
_security_group_rule = None
@@ -534,8 +530,8 @@ class TestCreateSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
'--ethertype', 'IPv4',
'--icmp-type', '3',
'--icmp-code', '11',
- '--project', identity_fakes.project_name,
- '--project-domain', identity_fakes.domain_name,
+ '--project', self.project.name,
+ '--project-domain', self.domain.name,
self._security_group.id,
]
self.assertRaises(tests_utils.ParserException,
@@ -743,7 +739,7 @@ class TestDeleteSecurityGroupRuleNetwork(TestSecurityGroupRuleNetwork):
self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.')
except exceptions.CommandError as e:
- self.assertEqual('1 of 2 rule failed to delete.', str(e))
+ self.assertEqual('1 of 2 rules failed to delete.', str(e))
self.network.find_security_group_rule.assert_any_call(
self._security_group_rules[0].id, ignore_missing=False)
@@ -823,7 +819,7 @@ class TestDeleteSecurityGroupRuleCompute(TestSecurityGroupRuleCompute):
self.cmd.take_action(parsed_args)
self.fail('CommandError should be raised.')
except exceptions.CommandError as e:
- self.assertEqual('1 of 2 rule failed to delete.', str(e))
+ self.assertEqual('1 of 2 rules failed to delete.', str(e))
self.compute.security_group_rules.delete.assert_any_call(
self._security_group_rules[0].id)
diff --git a/openstackclient/tests/network/v2/test_subnet.py b/openstackclient/tests/network/v2/test_subnet.py
index 99b558c0..e24b49e8 100644
--- a/openstackclient/tests/network/v2/test_subnet.py
+++ b/openstackclient/tests/network/v2/test_subnet.py
@@ -11,7 +11,6 @@
# under the License.
#
-import copy
import mock
from mock import call
@@ -36,10 +35,12 @@ class TestSubnet(network_fakes.TestNetworkV2):
class TestCreateSubnet(TestSubnet):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
# An IPv4 subnet to be created with mostly default values
_subnet = network_fakes.FakeSubnet.create_one_subnet(
attrs={
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': project.id,
}
)
@@ -49,7 +50,7 @@ class TestCreateSubnet(TestSubnet):
# An IPv4 subnet to be created using a specific subnet pool
_subnet_from_pool = network_fakes.FakeSubnet.create_one_subnet(
attrs={
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': project.id,
'subnetpool_id': _subnet_pool.id,
'dns_nameservers': ['8.8.8.8',
'8.8.4.4'],
@@ -63,7 +64,7 @@ class TestCreateSubnet(TestSubnet):
# An IPv6 subnet to be created with most options specified
_subnet_ipv6 = network_fakes.FakeSubnet.create_one_subnet(
attrs={
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': project.id,
'cidr': 'fe80:0:0:a00a::/64',
'enable_dhcp': True,
'dns_nameservers': ['fe80:27ff:a00a:f00f::ffff',
@@ -187,19 +188,11 @@ class TestCreateSubnet(TestSubnet):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# Get a shortcut to the DomainManager Mock
self.domains_mock = self.identity.domains
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
# Mock SDK calls for all tests.
self.network.find_network = mock.Mock(return_value=self._network)
@@ -243,7 +236,6 @@ class TestCreateSubnet(TestSubnet):
self.network.create_subnet.assert_called_once_with(**{
'cidr': self._subnet.cidr,
- 'enable_dhcp': self._subnet.enable_dhcp,
'ip_version': self._subnet.ip_version,
'name': self._subnet.name,
'network_id': self._subnet.network_id,
@@ -417,7 +409,6 @@ class TestCreateSubnet(TestSubnet):
self.network.create_subnet.assert_called_once_with(**{
'cidr': self._subnet.cidr,
- 'enable_dhcp': self._subnet.enable_dhcp,
'ip_version': self._subnet.ip_version,
'name': self._subnet.name,
'network_id': self._subnet.network_id,
@@ -767,3 +758,109 @@ class TestShowSubnet(TestSubnet):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
+
+
+class TestUnsetSubnet(TestSubnet):
+
+ def setUp(self):
+ super(TestUnsetSubnet, self).setUp()
+ self._testsubnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'dns_nameservers': ['8.8.8.8',
+ '8.8.8.4'],
+ 'host_routes': [{'destination': '10.20.20.0/24',
+ 'nexthop': '10.20.20.1'},
+ {'destination': '10.30.30.30/24',
+ 'nexthop': '10.30.30.1'}],
+ 'allocation_pools': [{'start': '8.8.8.100',
+ 'end': '8.8.8.150'},
+ {'start': '8.8.8.160',
+ 'end': '8.8.8.170'}], })
+ self.network.find_subnet = mock.Mock(return_value=self._testsubnet)
+ self.network.update_subnet = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = subnet_v2.UnsetSubnet(self.app, self.namespace)
+
+ def test_unset_subnet_params(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'dns_nameservers': ['8.8.8.4'],
+ 'host_routes': [{
+ "destination": "10.20.20.0/24", "nexthop": "10.20.20.1"}],
+ 'allocation_pools': [{'start': '8.8.8.160', 'end': '8.8.8.170'}],
+ }
+ self.network.update_subnet.assert_called_once_with(
+ self._testsubnet, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_subnet_wrong_host_routes(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.2',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.2"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_unset_subnet_wrong_allocation_pool(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.8',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.156',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.8']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.156'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
+
+ def test_unset_subnet_wrong_dns_nameservers(self):
+ arglist = [
+ '--dns-nameserver', '8.8.8.1',
+ '--host-route', 'destination=10.30.30.30/24,gateway=10.30.30.1',
+ '--allocation-pool', 'start=8.8.8.100,end=8.8.8.150',
+ self._testsubnet.name,
+ ]
+ verifylist = [
+ ('dns_nameservers', ['8.8.8.1']),
+ ('host_routes', [{
+ "destination": "10.30.30.30/24", "gateway": "10.30.30.1"}]),
+ ('allocation_pools', [{
+ 'start': '8.8.8.100', 'end': '8.8.8.150'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action, parsed_args)
diff --git a/openstackclient/tests/network/v2/test_subnet_pool.py b/openstackclient/tests/network/v2/test_subnet_pool.py
index 7a96b30f..8269af0b 100644
--- a/openstackclient/tests/network/v2/test_subnet_pool.py
+++ b/openstackclient/tests/network/v2/test_subnet_pool.py
@@ -12,7 +12,6 @@
#
import argparse
-import copy
import mock
from mock import call
@@ -37,6 +36,8 @@ class TestSubnetPool(network_fakes.TestNetworkV2):
class TestCreateSubnetPool(TestSubnetPool):
+ project = identity_fakes_v3.FakeProject.create_one_project()
+ domain = identity_fakes_v3.FakeDomain.create_one_domain()
# The new subnet pool to create.
_subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool()
@@ -93,19 +94,11 @@ class TestCreateSubnetPool(TestSubnetPool):
# Get a shortcut to the ProjectManager Mock
self.projects_mock = self.identity.projects
- self.projects_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.PROJECT),
- loaded=True,
- )
+ self.projects_mock.get.return_value = self.project
# Get a shortcut to the DomainManager Mock
self.domains_mock = self.identity.domains
- self.domains_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(identity_fakes_v3.DOMAIN),
- loaded=True,
- )
+ self.domains_mock.get.return_value = self.domain
def test_create_no_options(self):
arglist = []
@@ -191,14 +184,14 @@ class TestCreateSubnetPool(TestSubnetPool):
def test_create_project_domain(self):
arglist = [
'--pool-prefix', '10.0.10.0/24',
- "--project", identity_fakes_v3.project_name,
- "--project-domain", identity_fakes_v3.domain_name,
+ "--project", self.project.name,
+ "--project-domain", self.domain.name,
self._subnet_pool.name,
]
verifylist = [
('prefixes', ['10.0.10.0/24']),
- ('project', identity_fakes_v3.project_name),
- ('project_domain', identity_fakes_v3.domain_name),
+ ('project', self.project.name),
+ ('project_domain', self.domain.name),
('name', self._subnet_pool.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -207,7 +200,7 @@ class TestCreateSubnetPool(TestSubnetPool):
self.network.create_subnet_pool.assert_called_once_with(**{
'prefixes': ['10.0.10.0/24'],
- 'tenant_id': identity_fakes_v3.project_id,
+ 'tenant_id': self.project.id,
'name': self._subnet_pool.name,
})
self.assertEqual(self.columns, columns)
@@ -698,3 +691,42 @@ class TestShowSubnetPool(TestSubnetPool):
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
+
+
+class TestUnsetSubnetPool(TestSubnetPool):
+
+ def setUp(self):
+ super(TestUnsetSubnetPool, self).setUp()
+ self._subnetpool = network_fakes.FakeSubnetPool.create_one_subnet_pool(
+ {'prefixes': ['10.0.10.0/24', '10.1.10.0/24',
+ '10.2.10.0/24'], })
+ self.network.find_subnet_pool = mock.Mock(
+ return_value=self._subnetpool)
+ self.network.update_subnet_pool = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = subnet_pool.UnsetSubnetPool(self.app, self.namespace)
+
+ def test_unset_subnet_pool(self):
+ arglist = [
+ '--pool-prefix', '10.0.10.0/24',
+ '--pool-prefix', '10.1.10.0/24',
+ self._subnetpool.name,
+ ]
+ verifylist = [('prefixes', ['10.0.10.0/24', '10.1.10.0/24'])]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ attrs = {'prefixes': ['10.2.10.0/24']}
+ self.network.update_subnet_pool.assert_called_once_with(
+ self._subnetpool, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_subnet_pool_prefix_not_existent(self):
+ arglist = [
+ '--pool-prefix', '10.100.1.1/25',
+ self._subnetpool.name,
+ ]
+ verifylist = [('prefixes', ['10.100.1.1/25'])]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/volume/test_find_resource.py b/openstackclient/tests/volume/test_find_resource.py
index 227d6ca7..982b02f0 100644
--- a/openstackclient/tests/volume/test_find_resource.py
+++ b/openstackclient/tests/volume/test_find_resource.py
@@ -44,7 +44,9 @@ class TestFindResourceVolumes(test_utils.TestCase):
api.client.get = mock.Mock()
resp = mock.Mock()
body = {"volumes": [{"id": ID, 'display_name': NAME}]}
- api.client.get.side_effect = [Exception("Not found"), (resp, body)]
+ api.client.get.side_effect = [Exception("Not found"),
+ Exception("Not found"),
+ (resp, body)]
self.manager = volumes.VolumeManager(api)
def test_find(self):
@@ -66,7 +68,9 @@ class TestFindResourceVolumeSnapshots(test_utils.TestCase):
api.client.get = mock.Mock()
resp = mock.Mock()
body = {"snapshots": [{"id": ID, 'display_name': NAME}]}
- api.client.get.side_effect = [Exception("Not found"), (resp, body)]
+ api.client.get.side_effect = [Exception("Not found"),
+ Exception("Not found"),
+ (resp, body)]
self.manager = volume_snapshots.SnapshotManager(api)
def test_find(self):
diff --git a/openstackclient/tests/volume/v1/fakes.py b/openstackclient/tests/volume/v1/fakes.py
index 6c349866..2584d4b1 100644
--- a/openstackclient/tests/volume/v1/fakes.py
+++ b/openstackclient/tests/volume/v1/fakes.py
@@ -157,7 +157,7 @@ class FakeTransfer(object):
:param Dictionary attrs:
A dictionary with all attributes of Transfer Request
- :retrun:
+ :return:
A FakeResource object with volume_id, name, id.
"""
# Set default attribute
@@ -207,7 +207,7 @@ class FakeService(object):
:param Dictionary attrs:
A dictionary with all attributes of service
- :retrun:
+ :return:
A FakeResource object with host, status, etc.
"""
# Set default attribute
diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py
index 1cbbf68a..74e30a41 100644
--- a/openstackclient/tests/volume/v2/fakes.py
+++ b/openstackclient/tests/volume/v2/fakes.py
@@ -53,7 +53,7 @@ class FakeTransfer(object):
:param Dictionary attrs:
A dictionary with all attributes of Transfer Request
- :retrun:
+ :return:
A FakeResource object with volume_id, name, id.
"""
# Set default attribute
@@ -103,7 +103,7 @@ class FakeService(object):
:param Dictionary attrs:
A dictionary with all attributes of service
- :retrun:
+ :return:
A FakeResource object with host, status, etc.
"""
# Set default attribute
@@ -146,26 +146,6 @@ class FakeService(object):
return services
- @staticmethod
- def get_services(services=None, count=2):
- """Get an iterable MagicMock object with a list of faked services.
-
- If services list is provided, then initialize the Mock object with the
- list. Otherwise create one.
-
- :param List services:
- A list of FakeResource objects faking services
- :param Integer count:
- The number of services to be faked
- :return
- An iterable Mock object with side_effect set to a list of faked
- services
- """
- if services is None:
- services = FakeService.create_services(count)
-
- return mock.MagicMock(side_effect=services)
-
class FakeVolumeClient(object):
@@ -223,7 +203,7 @@ class FakeVolume(object):
:param Dictionary attrs:
A dictionary with all attributes of volume
- :retrun:
+ :return:
A FakeResource object with id, name, status, etc.
"""
attrs = attrs or {}
@@ -403,6 +383,7 @@ class FakeBackup(object):
"id": 'backup-id-' + uuid.uuid4().hex,
"name": 'backup-name-' + uuid.uuid4().hex,
"volume_id": 'volume-id-' + uuid.uuid4().hex,
+ "snapshot_id": 'snapshot-id' + uuid.uuid4().hex,
"description": 'description-' + uuid.uuid4().hex,
"object_count": None,
"container": 'container-' + uuid.uuid4().hex,
@@ -437,6 +418,26 @@ class FakeBackup(object):
return backups
+ @staticmethod
+ def get_backups(backups=None, count=2):
+ """Get an iterable MagicMock object with a list of faked backups.
+
+ If backups list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking backups
+ :param Integer count:
+ The number of backups to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ backups
+ """
+ if backups is None:
+ backups = FakeBackup.create_backups(count)
+
+ return mock.MagicMock(side_effect=backups)
+
class FakeExtension(object):
"""Fake one or more extension."""
@@ -548,6 +549,26 @@ class FakeQos(object):
return qoses
+ @staticmethod
+ def get_qoses(qoses=None, count=2):
+ """Get an iterable MagicMock object with a list of faked qoses.
+
+ If qoses list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking qoses
+ :param Integer count:
+ The number of qoses to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ qoses
+ """
+ if qoses is None:
+ qoses = FakeQos.create_qoses(count)
+
+ return mock.MagicMock(side_effect=qoses)
+
class FakeSnapshot(object):
"""Fake one or more snapshot."""
@@ -601,6 +622,26 @@ class FakeSnapshot(object):
return snapshots
+ @staticmethod
+ def get_snapshots(snapshots=None, count=2):
+ """Get an iterable MagicMock object with a list of faked snapshots.
+
+ If snapshots list is provided, then initialize the Mock object with the
+ list. Otherwise create one.
+
+ :param List volumes:
+ A list of FakeResource objects faking snapshots
+ :param Integer count:
+ The number of snapshots to be faked
+ :return
+ An iterable Mock object with side_effect set to a list of faked
+ snapshots
+ """
+ if snapshots is None:
+ snapshots = FakeSnapshot.create_snapshots(count)
+
+ return mock.MagicMock(side_effect=snapshots)
+
class FakeType(object):
"""Fake one or more type."""
diff --git a/openstackclient/tests/volume/v2/test_backup.py b/openstackclient/tests/volume/v2/test_backup.py
index ba0f1c18..3c2b3948 100644
--- a/openstackclient/tests/volume/v2/test_backup.py
+++ b/openstackclient/tests/volume/v2/test_backup.py
@@ -12,6 +12,12 @@
# under the License.
#
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
from openstackclient.tests.volume.v2 import fakes as volume_fakes
from openstackclient.volume.v2 import backup
@@ -25,6 +31,8 @@ class TestBackup(volume_fakes.TestVolume):
self.backups_mock.reset_mock()
self.volumes_mock = self.app.client_manager.volume.volumes
self.volumes_mock.reset_mock()
+ self.snapshots_mock = self.app.client_manager.volume.volume_snapshots
+ self.snapshots_mock.reset_mock()
self.restores_mock = self.app.client_manager.volume.restores
self.restores_mock.reset_mock()
@@ -32,8 +40,9 @@ class TestBackup(volume_fakes.TestVolume):
class TestBackupCreate(TestBackup):
volume = volume_fakes.FakeVolume.create_one_volume()
+ snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
new_backup = volume_fakes.FakeBackup.create_one_backup(
- attrs={'volume_id': volume.id})
+ attrs={'volume_id': volume.id, 'snapshot_id': snapshot.id})
columns = (
'availability_zone',
@@ -43,6 +52,7 @@ class TestBackupCreate(TestBackup):
'name',
'object_count',
'size',
+ 'snapshot_id',
'status',
'volume_id',
)
@@ -54,6 +64,7 @@ class TestBackupCreate(TestBackup):
new_backup.name,
new_backup.object_count,
new_backup.size,
+ new_backup.snapshot_id,
new_backup.status,
new_backup.volume_id,
)
@@ -62,6 +73,7 @@ class TestBackupCreate(TestBackup):
super(TestBackupCreate, self).setUp()
self.volumes_mock.get.return_value = self.volume
+ self.snapshots_mock.get.return_value = self.snapshot
self.backups_mock.create.return_value = self.new_backup
# Get the command object to test
@@ -73,6 +85,8 @@ class TestBackupCreate(TestBackup):
"--description", self.new_backup.description,
"--container", self.new_backup.container,
"--force",
+ "--incremental",
+ "--snapshot", self.new_backup.snapshot_id,
self.new_backup.volume_id,
]
verifylist = [
@@ -80,6 +94,8 @@ class TestBackupCreate(TestBackup):
("description", self.new_backup.description),
("container", self.new_backup.container),
("force", True),
+ ("incremental", True),
+ ("snapshot", self.new_backup.snapshot_id),
("volume", self.new_backup.volume_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -92,6 +108,8 @@ class TestBackupCreate(TestBackup):
name=self.new_backup.name,
description=self.new_backup.description,
force=True,
+ incremental=True,
+ snapshot_id=self.new_backup.snapshot_id,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -117,6 +135,8 @@ class TestBackupCreate(TestBackup):
name=None,
description=self.new_backup.description,
force=False,
+ incremental=False,
+ snapshot_id=None,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -124,12 +144,13 @@ class TestBackupCreate(TestBackup):
class TestBackupDelete(TestBackup):
- backup = volume_fakes.FakeBackup.create_one_backup()
+ backups = volume_fakes.FakeBackup.create_backups(count=2)
def setUp(self):
super(TestBackupDelete, self).setUp()
- self.backups_mock.get.return_value = self.backup
+ self.backups_mock.get = (
+ volume_fakes.FakeBackup.get_backups(self.backups))
self.backups_mock.delete.return_value = None
# Get the command object to mock
@@ -137,18 +158,81 @@ class TestBackupDelete(TestBackup):
def test_backup_delete(self):
arglist = [
- self.backup.id
+ self.backups[0].id
+ ]
+ verifylist = [
+ ("backups", [self.backups[0].id])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.backups_mock.delete.assert_called_with(
+ self.backups[0].id, False)
+ self.assertIsNone(result)
+
+ def test_backup_delete_with_force(self):
+ arglist = [
+ '--force',
+ self.backups[0].id,
]
verifylist = [
- ("backups", [self.backup.id])
+ ('force', True),
+ ("backups", [self.backups[0].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.backups_mock.delete.assert_called_with(self.backup.id)
+ self.backups_mock.delete.assert_called_with(self.backups[0].id, True)
self.assertIsNone(result)
+ def test_delete_multiple_backups(self):
+ arglist = []
+ for b in self.backups:
+ arglist.append(b.id)
+ verifylist = [
+ ('backups', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for b in self.backups:
+ calls.append(call(b.id, False))
+ self.backups_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_backups_with_exception(self):
+ arglist = [
+ self.backups[0].id,
+ 'unexist_backup',
+ ]
+ verifylist = [
+ ('backups', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.backups[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 backups failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.backups_mock, self.backups[0].id)
+ find_mock.assert_any_call(self.backups_mock, 'unexist_backup')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.backups_mock.delete.assert_called_once_with(
+ self.backups[0].id, False
+ )
+
class TestBackupList(TestBackup):
@@ -264,6 +348,7 @@ class TestBackupShow(TestBackup):
'name',
'object_count',
'size',
+ 'snapshot_id',
'status',
'volume_id',
)
@@ -275,6 +360,7 @@ class TestBackupShow(TestBackup):
backup.name,
backup.object_count,
backup.size,
+ backup.snapshot_id,
backup.status,
backup.volume_id,
)
diff --git a/openstackclient/tests/volume/v2/test_qos_specs.py b/openstackclient/tests/volume/v2/test_qos_specs.py
index 92ffca74..56b8ae03 100644
--- a/openstackclient/tests/volume/v2/test_qos_specs.py
+++ b/openstackclient/tests/volume/v2/test_qos_specs.py
@@ -13,9 +13,14 @@
# under the License.
#
+import mock
+from mock import call
+
+from osc_lib import exceptions
+from osc_lib import utils
+
from openstackclient.tests.volume.v2 import fakes as volume_fakes
from openstackclient.volume.v2 import qos_specs
-from osc_lib import utils
class TestQos(volume_fakes.TestVolume):
@@ -155,45 +160,94 @@ class TestQosCreate(TestQos):
class TestQosDelete(TestQos):
- qos_spec = volume_fakes.FakeQos.create_one_qos()
+ qos_specs = volume_fakes.FakeQos.create_qoses(count=2)
def setUp(self):
super(TestQosDelete, self).setUp()
- self.qos_mock.get.return_value = self.qos_spec
+ self.qos_mock.get = (
+ volume_fakes.FakeQos.get_qoses(self.qos_specs))
# Get the command object to test
self.cmd = qos_specs.DeleteQos(self.app, None)
def test_qos_delete(self):
arglist = [
- self.qos_spec.id
+ self.qos_specs[0].id
]
verifylist = [
- ('qos_specs', [self.qos_spec.id])
+ ('qos_specs', [self.qos_specs[0].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.delete.assert_called_with(self.qos_spec.id, False)
+ self.qos_mock.delete.assert_called_with(
+ self.qos_specs[0].id, False)
self.assertIsNone(result)
def test_qos_delete_with_force(self):
arglist = [
'--force',
- self.qos_spec.id
+ self.qos_specs[0].id
]
verifylist = [
('force', True),
- ('qos_specs', [self.qos_spec.id])
+ ('qos_specs', [self.qos_specs[0].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.delete.assert_called_with(self.qos_spec.id, True)
+ self.qos_mock.delete.assert_called_with(
+ self.qos_specs[0].id, True)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_qoses(self):
+ arglist = []
+ for q in self.qos_specs:
+ arglist.append(q.id)
+ verifylist = [
+ ('qos_specs', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for q in self.qos_specs:
+ calls.append(call(q.id, False))
+ self.qos_mock.delete.assert_has_calls(calls)
self.assertIsNone(result)
+ def test_delete_multiple_qoses_with_exception(self):
+ arglist = [
+ self.qos_specs[0].id,
+ 'unexist_qos',
+ ]
+ verifylist = [
+ ('qos_specs', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.qos_specs[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual(
+ '1 of 2 QoS specifications failed to delete.', str(e))
+
+ find_mock.assert_any_call(self.qos_mock, self.qos_specs[0].id)
+ find_mock.assert_any_call(self.qos_mock, 'unexist_qos')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.qos_mock.delete.assert_called_once_with(
+ self.qos_specs[0].id, False
+ )
+
class TestQosDisassociate(TestQos):
diff --git a/openstackclient/tests/volume/v2/test_snapshot.py b/openstackclient/tests/volume/v2/test_snapshot.py
index ef199cbc..04e0285e 100644
--- a/openstackclient/tests/volume/v2/test_snapshot.py
+++ b/openstackclient/tests/volume/v2/test_snapshot.py
@@ -12,6 +12,10 @@
# under the License.
#
+import mock
+from mock import call
+
+from osc_lib import exceptions
from osc_lib import utils
from openstackclient.tests.volume.v2 import fakes as volume_fakes
@@ -70,12 +74,15 @@ class TestSnapshotCreate(TestSnapshot):
"--name", self.new_snapshot.name,
"--description", self.new_snapshot.description,
"--force",
+ '--property', 'Alpha=a',
+ '--property', 'Beta=b',
self.new_snapshot.volume_id,
]
verifylist = [
("name", self.new_snapshot.name),
("description", self.new_snapshot.description),
("force", True),
+ ('property', {'Alpha': 'a', 'Beta': 'b'}),
("volume", self.new_snapshot.volume_id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -86,7 +93,8 @@ class TestSnapshotCreate(TestSnapshot):
self.new_snapshot.volume_id,
force=True,
name=self.new_snapshot.name,
- description=self.new_snapshot.description
+ description=self.new_snapshot.description,
+ metadata={'Alpha': 'a', 'Beta': 'b'},
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -110,7 +118,8 @@ class TestSnapshotCreate(TestSnapshot):
self.new_snapshot.volume_id,
force=True,
name=None,
- description=self.new_snapshot.description
+ description=self.new_snapshot.description,
+ metadata=None,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
@@ -118,12 +127,13 @@ class TestSnapshotCreate(TestSnapshot):
class TestSnapshotDelete(TestSnapshot):
- snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+ snapshots = volume_fakes.FakeSnapshot.create_snapshots(count=2)
def setUp(self):
super(TestSnapshotDelete, self).setUp()
- self.snapshots_mock.get.return_value = self.snapshot
+ self.snapshots_mock.get = (
+ volume_fakes.FakeSnapshot.get_snapshots(self.snapshots))
self.snapshots_mock.delete.return_value = None
# Get the command object to mock
@@ -131,18 +141,66 @@ class TestSnapshotDelete(TestSnapshot):
def test_snapshot_delete(self):
arglist = [
- self.snapshot.id
+ self.snapshots[0].id
]
verifylist = [
- ("snapshots", [self.snapshot.id])
+ ("snapshots", [self.snapshots[0].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.snapshots_mock.delete.assert_called_with(self.snapshot.id)
+ self.snapshots_mock.delete.assert_called_with(
+ self.snapshots[0].id)
self.assertIsNone(result)
+ def test_delete_multiple_snapshots(self):
+ arglist = []
+ for s in self.snapshots:
+ arglist.append(s.id)
+ verifylist = [
+ ('snapshots', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for s in self.snapshots:
+ calls.append(call(s.id))
+ self.snapshots_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_snapshots_with_exception(self):
+ arglist = [
+ self.snapshots[0].id,
+ 'unexist_snapshot',
+ ]
+ verifylist = [
+ ('snapshots', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self.snapshots[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 snapshots failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(
+ self.snapshots_mock, self.snapshots[0].id)
+ find_mock.assert_any_call(self.snapshots_mock, 'unexist_snapshot')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.snapshots_mock.delete.assert_called_once_with(
+ self.snapshots[0].id
+ )
+
class TestSnapshotList(TestSnapshot):
diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py
index 174f33f2..a7db2e49 100644
--- a/openstackclient/tests/volume/v2/test_type.py
+++ b/openstackclient/tests/volume/v2/test_type.py
@@ -14,6 +14,7 @@
import copy
+from osc_lib import exceptions
from osc_lib import utils
from openstackclient.tests import fakes
@@ -41,6 +42,7 @@ class TestType(volume_fakes.TestVolume):
class TestTypeCreate(TestType):
+ project = identity_fakes.FakeProject.create_one_project()
columns = (
'description',
'id',
@@ -58,6 +60,7 @@ class TestTypeCreate(TestType):
)
self.types_mock.create.return_value = self.new_volume_type
+ self.projects_mock.get.return_value = self.project
# Get the command object to test
self.cmd = volume_type.CreateVolumeType(self.app, None)
@@ -89,12 +92,14 @@ class TestTypeCreate(TestType):
arglist = [
"--description", self.new_volume_type.description,
"--private",
+ "--project", self.project.id,
self.new_volume_type.name,
]
verifylist = [
("description", self.new_volume_type.description),
("public", False),
("private", True),
+ ("project", self.project.id),
("name", self.new_volume_type.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -109,6 +114,21 @@ class TestTypeCreate(TestType):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
+ def test_public_type_create_with_project(self):
+ arglist = [
+ '--project', self.project.id,
+ self.new_volume_type.name,
+ ]
+ verifylist = [
+ ('project', self.project.id),
+ ('name', self.new_volume_type.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
class TestTypeDelete(TestType):
diff --git a/openstackclient/tests/volume/v2/test_volume.py b/openstackclient/tests/volume/v2/test_volume.py
index 68158df0..db65c3bd 100644
--- a/openstackclient/tests/volume/v2/test_volume.py
+++ b/openstackclient/tests/volume/v2/test_volume.py
@@ -13,9 +13,10 @@
#
import copy
-
+import mock
from mock import call
+from osc_lib import exceptions
from osc_lib import utils
from openstackclient.tests import fakes
@@ -458,6 +459,36 @@ class TestVolumeDelete(TestVolume):
self.volumes_mock.delete.assert_has_calls(calls)
self.assertIsNone(result)
+ def test_volume_delete_multi_volumes_with_exception(self):
+ volumes = self.setup_volumes_mock(count=2)
+
+ arglist = [
+ volumes[0].id,
+ 'unexist_volume',
+ ]
+ verifylist = [
+ ('volumes', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [volumes[0], exceptions.CommandError]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 volumes failed to delete.',
+ str(e))
+
+ find_mock.assert_any_call(self.volumes_mock, volumes[0].id)
+ find_mock.assert_any_call(self.volumes_mock, 'unexist_volume')
+
+ self.assertEqual(2, find_mock.call_count)
+ self.volumes_mock.delete.assert_called_once_with(
+ volumes[0].id
+ )
+
class TestVolumeList(TestVolume):
diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py
index e11aa1a7..820673bb 100644
--- a/openstackclient/volume/v1/volume.py
+++ b/openstackclient/volume/v1/volume.py
@@ -175,7 +175,6 @@ class DeleteVolume(command.Command):
)
parser.add_argument(
'--force',
- dest='force',
action='store_true',
default=False,
help=_('Attempt forced removal of volume(s), regardless of state '
diff --git a/openstackclient/volume/v2/backup.py b/openstackclient/volume/v2/backup.py
index 519913a9..3d27c121 100644
--- a/openstackclient/volume/v2/backup.py
+++ b/openstackclient/volume/v2/backup.py
@@ -15,14 +15,19 @@
"""Volume v2 Backup action implementations"""
import copy
+import logging
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateBackup(command.ShowOne):
"""Create new backup"""
@@ -49,23 +54,40 @@ class CreateBackup(command.ShowOne):
help=_("Optional backup container name")
)
parser.add_argument(
+ "--snapshot",
+ metavar="<snapshot>",
+ help=_("Snapshot to backup (name or ID)")
+ )
+ parser.add_argument(
'--force',
action='store_true',
default=False,
help=_("Allow to back up an in-use volume")
)
+ parser.add_argument(
+ '--incremental',
+ action='store_true',
+ default=False,
+ help=_("Perform an incremental backup")
+ )
return parser
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
volume_id = utils.find_resource(
volume_client.volumes, parsed_args.volume).id
+ snapshot_id = None
+ if parsed_args.snapshot:
+ snapshot_id = utils.find_resource(
+ volume_client.volume_snapshots, parsed_args.snapshot).id
backup = volume_client.backups.create(
volume_id,
container=parsed_args.container,
name=parsed_args.name,
description=parsed_args.description,
force=parsed_args.force,
+ incremental=parsed_args.incremental,
+ snapshot_id=snapshot_id,
)
backup._info.pop("links", None)
return zip(*sorted(six.iteritems(backup._info)))
@@ -82,14 +104,34 @@ class DeleteBackup(command.Command):
nargs="+",
help=_("Backup(s) to delete (name or ID)")
)
+ parser.add_argument(
+ '--force',
+ action='store_true',
+ default=False,
+ help=_("Allow delete in state other than error or available")
+ )
return parser
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- for backup in parsed_args.backups:
- backup_id = utils.find_resource(
- volume_client.backups, backup).id
- volume_client.backups.delete(backup_id)
+ result = 0
+
+ for i in parsed_args.backups:
+ try:
+ backup_id = utils.find_resource(
+ volume_client.backups, i).id
+ volume_client.backups.delete(backup_id, parsed_args.force)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete backup with "
+ "name or ID '%(backup)s': %(e)s")
+ % {'backup': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.backups)
+ msg = (_("%(result)s of %(total)s backups failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListBackup(command.Lister):
diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py
index 5ed1225b..9797f1a6 100644
--- a/openstackclient/volume/v2/qos_specs.py
+++ b/openstackclient/volume/v2/qos_specs.py
@@ -15,14 +15,20 @@
"""Volume v2 QoS action implementations"""
+import logging
+
from osc_lib.cli import parseractions
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class AssociateQos(command.Command):
"""Associate a QoS specification to a volume type"""
@@ -113,9 +119,23 @@ class DeleteQos(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- 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, parsed_args.force)
+ result = 0
+
+ for i in parsed_args.qos_specs:
+ try:
+ qos_spec = utils.find_resource(volume_client.qos_specs, i)
+ volume_client.qos_specs.delete(qos_spec.id, parsed_args.force)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete QoS specification with "
+ "name or ID '%(qos)s': %(e)s")
+ % {'qos': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.qos_specs)
+ msg = (_("%(result)s of %(total)s QoS specifications failed"
+ " to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class DisassociateQos(command.Command):
diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py
index 439904e7..ba692074 100644
--- a/openstackclient/volume/v2/snapshot.py
+++ b/openstackclient/volume/v2/snapshot.py
@@ -15,15 +15,20 @@
"""Volume v2 snapshot action implementations"""
import copy
+import logging
from osc_lib.cli import parseractions
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
from openstackclient.i18n import _
+LOG = logging.getLogger(__name__)
+
+
class CreateSnapshot(command.ShowOne):
"""Create new snapshot"""
@@ -46,12 +51,18 @@ class CreateSnapshot(command.ShowOne):
)
parser.add_argument(
"--force",
- dest="force",
action="store_true",
default=False,
help=_("Create a snapshot attached to an instance. "
"Default is False")
)
+ parser.add_argument(
+ "--property",
+ metavar="<key=value>",
+ action=parseractions.KeyValueAction,
+ help=_("Set a property to this snapshot "
+ "(repeat option to set multiple properties)"),
+ )
return parser
def take_action(self, parsed_args):
@@ -62,7 +73,8 @@ class CreateSnapshot(command.ShowOne):
volume_id,
force=parsed_args.force,
name=parsed_args.name,
- description=parsed_args.description
+ description=parsed_args.description,
+ metadata=parsed_args.property,
)
snapshot._info.update(
{'properties': utils.format_dict(snapshot._info.pop('metadata'))}
@@ -85,10 +97,24 @@ class DeleteSnapshot(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- for snapshot in parsed_args.snapshots:
- snapshot_id = utils.find_resource(
- volume_client.volume_snapshots, snapshot).id
- volume_client.volume_snapshots.delete(snapshot_id)
+ result = 0
+
+ for i in parsed_args.snapshots:
+ try:
+ snapshot_id = utils.find_resource(
+ volume_client.volume_snapshots, i).id
+ volume_client.volume_snapshots.delete(snapshot_id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete snapshot with "
+ "name or ID '%(snapshot)s': %(e)s")
+ % {'snapshot': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.snapshots)
+ msg = (_("%(result)s of %(total)s snapshots failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListSnapshot(command.Lister):
diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py
index be2388fb..85f267ef 100644
--- a/openstackclient/volume/v2/volume.py
+++ b/openstackclient/volume/v2/volume.py
@@ -19,6 +19,7 @@ import logging
from osc_lib.cli import parseractions
from osc_lib.command import command
+from osc_lib import exceptions
from osc_lib import utils
import six
@@ -167,7 +168,6 @@ class DeleteVolume(command.Command):
)
parser.add_argument(
"--force",
- dest="force",
action="store_true",
default=False,
help=_("Attempt forced removal of volume(s), regardless of state "
@@ -177,13 +177,27 @@ class DeleteVolume(command.Command):
def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume
- for volume in parsed_args.volumes:
- volume_obj = utils.find_resource(
- volume_client.volumes, volume)
- if parsed_args.force:
- volume_client.volumes.force_delete(volume_obj.id)
- else:
- volume_client.volumes.delete(volume_obj.id)
+ result = 0
+
+ for i in parsed_args.volumes:
+ try:
+ volume_obj = utils.find_resource(
+ volume_client.volumes, i)
+ if parsed_args.force:
+ volume_client.volumes.force_delete(volume_obj.id)
+ else:
+ volume_client.volumes.delete(volume_obj.id)
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to delete volume with "
+ "name or ID '%(volume)s': %(e)s")
+ % {'volume': i, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.volumes)
+ msg = (_("%(result)s of %(total)s volumes failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListVolume(command.Lister):
diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py
index 87f4c547..ac11785c 100644
--- a/openstackclient/volume/v2/volume_type.py
+++ b/openstackclient/volume/v2/volume_type.py
@@ -47,14 +47,12 @@ class CreateVolumeType(command.ShowOne):
public_group = parser.add_mutually_exclusive_group()
public_group.add_argument(
"--public",
- dest="public",
action="store_true",
default=False,
help=_("Volume type is accessible to the public"),
)
public_group.add_argument(
"--private",
- dest="private",
action="store_true",
default=False,
help=_("Volume type is not accessible to the public"),
@@ -66,12 +64,23 @@ class CreateVolumeType(command.ShowOne):
help=_('Set a property on this volume type '
'(repeat option to set multiple properties)'),
)
+ parser.add_argument(
+ '--project',
+ metavar='<project>',
+ help=_("Allow <project> to access private type (name or ID) "
+ "(Must be used with --private option)"),
+ )
+ identity_common.add_project_domain_option_to_parser(parser)
return parser
def take_action(self, parsed_args):
-
+ identity_client = self.app.client_manager.identity
volume_client = self.app.client_manager.volume
+ if parsed_args.project and not parsed_args.private:
+ msg = _("--project is only allowed with --private")
+ raise exceptions.CommandError(msg)
+
kwargs = {}
if parsed_args.public:
kwargs['is_public'] = True
@@ -84,6 +93,20 @@ class CreateVolumeType(command.ShowOne):
**kwargs
)
volume_type._info.pop('extra_specs')
+
+ if parsed_args.project:
+ try:
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ volume_client.volume_type_access.add_project_access(
+ volume_type.id, project_id)
+ except Exception as e:
+ msg = _("Failed to add project %(project)s access to "
+ "type: %(e)s")
+ LOG.error(msg % {'project': parsed_args.project, 'e': e})
if parsed_args.property:
result = volume_type.set_keys(parsed_args.property)
volume_type._info.update({'properties': utils.format_dict(result)})