diff options
| author | Thomas Goirand <zigo@debian.org> | 2015-09-26 19:37:25 +0000 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2015-09-27 04:10:17 +0000 |
| commit | ebeeea8f7893f20d811b5ac6cf1137787419cccd (patch) | |
| tree | 77b1268ef539955f427306a909080847578d20cf | |
| parent | 3b23dabb641692af41b4988583a0c80698ea94c1 (diff) | |
1.7.0-1 (patches unapplied)import/1.7.0-1ubuntu/wily-proposedubuntu/wily-develubuntu/wily
Imported using git-ubuntu import.
Notes
Notes:
* New upstream release.
* Fixed (build-)depends for this release.
84 files changed, 2011 insertions, 469 deletions
diff --git a/.coveragerc b/.coveragerc index 9c8f046..2651b2f 100644 --- a/.coveragerc +++ b/.coveragerc @@ -4,4 +4,4 @@ source = openstackclient omit = openstackclient/openstack/* [report] -ignore-errors = True +ignore_errors = True diff --git a/debian/changelog b/debian/changelog index 01ae560..5e2465d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +python-openstackclient (1.7.0-1) experimental; urgency=medium + + * New upstream release. + * Fixed (build-)depends for this release. + + -- Thomas Goirand <zigo@debian.org> Sat, 26 Sep 2015 19:37:25 +0000 + python-openstackclient (1.6.0-1) experimental; urgency=medium [ gustavo panizzo ] diff --git a/debian/control b/debian/control index 67c3fb4..7ae2058 100644 --- a/debian/control +++ b/debian/control @@ -8,7 +8,7 @@ Build-Depends: debhelper (>= 9), dh-python, openstack-pkg-tools, python-all, - python-pbr (>= 1.6), + python-pbr (>= 1.8), python-setuptools, python-sphinx, Build-Depends-Indep: cliff-tablib, @@ -24,20 +24,20 @@ Build-Depends-Indep: cliff-tablib, python-keystoneclient (>= 1:1.6.0), python-mock (>= 1.3), python-neutronclient (>= 1:2.6.0), - python-novaclient (>= 2:2.26.0), + python-novaclient (>= 2:2.28.1), python-os-client-config (>= 1.4.0), python-os-testr, - python-oslo.config (>= 1:1.11.0), + python-oslo.config (>= 1:2.3.0), python-oslo.i18n (>= 1.5.0), python-oslo.serialization (>= 1.2.0), - python-oslo.utils (>= 1.9.0), + python-oslo.utils (>= 2.0.0), python-oslosphinx (>= 2.5.0), python-oslotest (>= 1.10.0), python-requests (>= 2.5.2), python-requests-mock (>= 0.6.0), python-six (>= 1.9.0), python-stevedore (>= 1.5.0), - python-tempest-lib (>= 0.6.1), + python-tempest-lib (>= 0.8.0), python-testtools (>= 1.4.0), python-webob, subunit, @@ -58,13 +58,13 @@ Depends: cliff-tablib, python-keyring, python-keystoneclient (>= 1:1.6.0), python-neutronclient (>= 1:2.6.0), - python-novaclient (>= 2:2.26.0), + python-novaclient (>= 2:2.28.1), python-os-client-config (>= 1.4.0), - python-oslo.config (>= 1:1.11.0), + python-oslo.config (>= 1:2.3.0), python-oslo.i18n (>= 1.5.0), python-oslo.serialization (>= 1.2.0), - python-oslo.utils (>= 1.9.0), - python-pbr (>= 1.6), + python-oslo.utils (>= 2.0.0), + python-pbr (>= 1.8), python-requests (>= 2.5.2), python-six (>= 1.9.0), python-stevedore (>= 1.5.0), diff --git a/doc/source/command-objects/image.rst b/doc/source/command-objects/image.rst index 2574142..8e44f51 100644 --- a/doc/source/command-objects/image.rst +++ b/doc/source/command-objects/image.rst @@ -7,7 +7,7 @@ Image v1, v2 image create ------------ -*Only supported for Image v1* +*Image v1, v2* Create/upload an image @@ -32,6 +32,7 @@ Create/upload an image [--protected | --unprotected] [--public | --private] [--property <key=value> [...] ] + [--tag <tag> [...] ] <image-name> .. option:: --id <id> @@ -42,6 +43,8 @@ Create/upload an image Upload image to this store + *Image version 1 only.* + .. option:: --container-format <container-format> Image container format (default: bare) @@ -54,10 +57,14 @@ Create/upload an image Image owner project name or ID + *Image version 1 only.* + .. option:: --size <size> Image size, in bytes (only used with --location and --copy-from) + *Image version 1 only.* + .. option:: --min-disk <disk-gb> Minimum disk size needed to boot image, in gigabytes @@ -70,10 +77,14 @@ Create/upload an image Download image from an existing URL + *Image version 1 only.* + .. option:: --copy-from <image-url> Copy image from the data store (similar to --location) + *Image version 1 only.* + .. option:: --file <file> Upload image from local file @@ -90,6 +101,8 @@ Create/upload an image Image hash used for verification + *Image version 1 only.* + .. option:: --protected Prevent image from being deleted @@ -110,6 +123,12 @@ Create/upload an image Set a property on this image (repeat for multiple values) +.. option:: --tag <tag> + + Set a tag on this image (repeat for multiple values) + + .. versionadded:: 2 + .. describe:: <image-name> New image name diff --git a/doc/source/command-objects/role.rst b/doc/source/command-objects/role.rst index 9ba149e..48751ed 100644 --- a/doc/source/command-objects/role.rst +++ b/doc/source/command-objects/role.rst @@ -20,21 +20,21 @@ Add role to a user or group in a project or domain .. option:: --domain <domain> - Include `<domain>` (name or ID) + Include <domain> (name or ID) .. versionadded:: 3 .. option:: --project <project> - Include `<project>` (name or ID) + Include <project> (name or ID) .. option:: --user <user> - Include `<user>` (name or ID) + Include <user> (name or ID) .. option:: --group <group> - Include `<group>` (name or ID) + Include <group> (name or ID) .. versionadded:: 3 @@ -67,7 +67,7 @@ Add role to a user or group in a project or domain .. describe:: <role> - Role to add to `<project>`:`<user>` (name or ID) + Role to add to <project>:<user> (name or ID) role create ----------- @@ -186,21 +186,21 @@ Remove role from domain/project : user/group .. option:: --domain <domain> - Include `<domain>` (name or ID) + Include <domain> (name or ID) .. versionadded:: 3 .. option:: --project <project> - Include `<project>` (name or ID) + Include <project> (name or ID) .. option:: --user <user> - Include `<user>` (name or ID) + Include <user> (name or ID) .. option:: --group <group> - Include `<group>` (name or ID) + Include <group> (name or ID) .. versionadded:: 3 diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst index eb61bab..9ff4843 100644 --- a/doc/source/command-objects/server.rst +++ b/doc/source/command-objects/server.rst @@ -185,6 +185,7 @@ List servers [--image <image>] [--host <hostname>] [--all-projects] + [--project <project> [--project-domain <project-domain>]] [--long] .. option:: --reservation-id <reservation-id> @@ -227,6 +228,24 @@ List servers Include all projects (admin only) +.. option:: --project <project> + + Search by project (admin only) (name or ID) + +.. option:: --project-domain <project-domain> + + Domain the project belongs to (name or ID). + This can be used in case collisions between project names exist. + +.. option:: --user <user> + + Search by user (admin only) (name or ID) + +.. option:: --user-domain <user-domain> + + Domain the user belongs to (name or ID). + This can be used in case collisions between user names exist. + .. option:: --long List additional fields in output diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst index 563a719..c770014 100644 --- a/doc/source/configuration.rst +++ b/doc/source/configuration.rst @@ -143,3 +143,74 @@ Debugging You may find the :doc:`config show <command-objects/config>` helpful to debug configuration issues. It will display your current configuration. + +Logging Settings +---------------- + +By setting `log_level` or `log_file` in the configuration +:file:`clouds.yaml`, a user may enable additional logging:: + + clouds: + devstack: + auth: + auth_url: http://192.168.122.10:35357/ + project_name: demo + username: demo + password: 0penstack + region_name: RegionOne + operation_log: + logging: TRUE + file: /tmp/openstackclient_demo.log + level: info + ds-admin: + auth: + auth_url: http://192.168.122.10:35357/ + project_name: admin + username: admin + password: 0penstack + region_name: RegionOne + log_file: /tmp/openstackclient_admin.log + log_level: debug + +:dfn:`log_file`: ``</path/file-name>`` + Full path to logging file. +:dfn:`log_level`: ``error`` | ``info`` | ``debug`` + If log level is not set, ``warning`` will be used. + +If log level is ``info``, the following information is recorded: + +* cloud name +* user name +* project name +* CLI start time (logging start time) +* CLI end time +* CLI arguments +* CLI return value +* and any ``info`` messages. + +If log level is ``debug``, the following information is recorded: + +* cloud name +* user name +* project name +* CLI start time (logging start time) +* CLI end time +* CLI arguments +* CLI return value +* API request header/body +* API response header/body +* and any ``debug`` messages. + +When a command is executed, these logs are saved every time. Recording the user +operations can help to identify resource changes and provide useful information +for troubleshooting. + +If saving the output of a single command use the `--log-file` option instead. + +* `--log-file <LOG_FILE>` + +The logging level for `--log-file` can be set by using following options. + +* `-v, --verbose` +* `-q, --quiet` +* `--debug` diff --git a/doc/source/developing.rst b/doc/source/developing.rst index f13241f..90f0900 100644 --- a/doc/source/developing.rst +++ b/doc/source/developing.rst @@ -2,6 +2,16 @@ Developing with OpenStackClient =============================== +Communication +------------- + +Meetings +========= +The OpenStackClient team meets regularly on every Thursday. For details +please refer to the `wiki`_. + +.. _`wiki`: https://wiki.openstack.org/wiki/Meetings/OpenStackClient + Testing ------- @@ -87,3 +97,20 @@ create HTML docs, run the following: $ tox -e docs The resultant HTML will be the ``doc/build/html`` directory. + +Testing new code +---------------- + +If a developer wants to test new code (feature, command or option) that +they have written, OpenStackClient may be installed from source by running +the following commands in the base directory of the project: + +.. code-block:: bash + + $ python setup.py develop + +or + +.. code-block:: bash + + $ pip install -e diff --git a/doc/source/man/openstack.rst b/doc/source/man/openstack.rst index 53bf362..3e47635 100644 --- a/doc/source/man/openstack.rst +++ b/doc/source/man/openstack.rst @@ -123,6 +123,18 @@ OPTIONS :option:`--os-interface` <interface> Interface type. Valid options are `public`, `admin` and `internal`. +:option:`--log-file` <LOGFILE> + Specify a file to log output. Disabled by default. + +:option:`-v, --verbose` + Increase verbosity of output. Can be repeated. + +:option:`-q, --quiet` + suppress output except warnings and errors + +:option:`--debug` + show tracebacks on errors and set verbosity to debug + COMMANDS ======== @@ -240,6 +252,15 @@ When :option:`--os-token` and :option:`--os-url` are both present the :option:`--os-auth-url` and :option:`--os-username` are present ``password`` auth type is selected. +Logging Settings +---------------- + +:program:`openstack` can record the operation history by logging settings +in configuration file. Recording the user operation, it can identify the +change of the resource and it becomes useful information for troubleshooting. + +See :doc:`../configuration` about Logging Settings for more details. + NOTES ===== diff --git a/doc/source/plugins.rst b/doc/source/plugins.rst index 8102c97..469742d 100644 --- a/doc/source/plugins.rst +++ b/doc/source/plugins.rst @@ -28,7 +28,7 @@ python-barbicanclient patch in progress (https://review.openstack.org/# python-ceilometerclient using argparse python-congressclient using OpenStackClient python-cueclient using OpenStackClient -python-designateclient uses cliff, but not OpenStackClient +python-designateclient patch in progress (https://review.openstack.org/#/c/133676/) python-heatclient patch in progress (https://review.openstack.org/#/c/195867/) python-ironicclient patch in progress (https://review.openstack.org/#/c/171672/) python-magnumclient using argparse diff --git a/doc/source/releases.rst b/doc/source/releases.rst index 5dd6771..526b163 100644 --- a/doc/source/releases.rst +++ b/doc/source/releases.rst @@ -2,6 +2,48 @@ Release Notes ============= +1.7.0 (22 Sep 2015) +=================== + +* Add support for v2 image create/update commands + Bug `1405562 <https://bugs.launchpad.net/bugs/1405562>`_ + +* ICMP secgroup rule must have ``--dst-port -1`` to actually allow ICMP + Bug `1477629 <https://bugs.launchpad.net/bugs/1477629>`_ + +* Add a blurb about ``pip install -e .`` to the developer docs + Bug `1483384 <https://bugs.launchpad.net/bugs/1483384>`_ + +* Add filtering by user for command 'openstack server list' + Bug `1483974 <https://bugs.launchpad.net/bugs/1483974>`_ + +* No support for listing servers of other project with openstack server list + Bug `1488486 <https://bugs.launchpad.net/bugs/1488486>`_ + +* Missing image causes confusing 'server show' response + Bug `1489901 <https://bugs.launchpad.net/bugs/1489901>`_ + +* Volume Attached to is incorrect + Bug `1489954 <https://bugs.launchpad.net/bugs/1489954>`_ + +* novaclient 2.27.0 breaks version handling + Bug `1492467 <https://bugs.launchpad.net/bugs/1492467>`_ + +* Support listing users in a non-default domain scoped group + Bug `1492916 <https://bugs.launchpad.net/bugs/1492916>`_ + +* ERROR: InvocationError: + '/opt/stack/new/python-openstackclient/.tox/functional/bin/ostestr' + in gate-osc-dsvm-functional + Bug `1496337 <https://bugs.launchpad.net/bugs/1496337>`_ + +* image list --long is broken with v2 + Bug `1498150 <https://bugs.launchpad.net/bugs/1498150>`_ + +* Add ``--log-file`` option support + +* Set default Volume API version to ``2`` + 1.6.0 (10 Aug 2015) =================== diff --git a/functional/tests/compute/v2/test_server.py b/functional/tests/compute/v2/test_server.py index aa1c120..a6cc98e 100644 --- a/functional/tests/compute/v2/test_server.py +++ b/functional/tests/compute/v2/test_server.py @@ -15,6 +15,7 @@ import uuid import testtools +from functional.common import exceptions from functional.common import test @@ -28,18 +29,37 @@ class ServerTests(test.TestCase): IP_POOL = 'public' @classmethod + def get_flavor(cls): + raw_output = cls.openstack('flavor list -f value -c ID') + ray = raw_output.split('\n') + idx = len(ray)/2 + return ray[idx] + + @classmethod + def get_image(cls): + raw_output = cls.openstack('image list -f value -c ID') + ray = raw_output.split('\n') + idx = len(ray)/2 + return ray[idx] + + @classmethod + def get_network(cls): + try: + raw_output = cls.openstack('network list -f value -c ID') + except exceptions.CommandFailed: + return '' + ray = raw_output.split('\n') + idx = len(ray)/2 + return ' --nic net-id=' + ray[idx] + + @classmethod def setUpClass(cls): opts = cls.get_show_opts(cls.FIELDS) - # TODO(thowe): pull these values from clouds.yaml - flavor = '4' - image = 'cirros-0.3.4-x86_64-uec' - netid = '' - if netid: - nicargs = ' --nic net-id=' + netid - else: - nicargs = '' + flavor = cls.get_flavor() + image = cls.get_image() + network = cls.get_network() raw_output = cls.openstack('server create --flavor ' + flavor + - ' --image ' + image + nicargs + ' ' + + ' --image ' + image + network + ' ' + cls.NAME + opts) expected = cls.NAME + '\n' cls.assertOutput(expected, raw_output) diff --git a/functional/tests/identity/v3/test_identity.py b/functional/tests/identity/v3/test_identity.py index bf3da16..dd5f2f4 100644 --- a/functional/tests/identity/v3/test_identity.py +++ b/functional/tests/identity/v3/test_identity.py @@ -28,7 +28,7 @@ class IdentityTests(test.TestCase): TOKEN_FIELDS = ['expires', 'id', 'project_id', 'user_id'] USER_FIELDS = ['email', 'enabled', 'id', 'name', 'name', 'domain_id', 'default_project_id', 'description'] - PROJECT_FIELDS = ['description', 'id', 'domain_id', + PROJECT_FIELDS = ['description', 'id', 'domain_id', 'is_domain', 'enabled', 'name', 'parent_id', 'links'] ROLE_FIELDS = ['id', 'name', 'links'] SERVICE_FIELDS = ['id', 'enabled', 'name', 'type', 'description'] @@ -43,6 +43,7 @@ class IdentityTests(test.TestCase): 'Enabled', 'Interface', 'URL'] IDENTITY_PROVIDER_FIELDS = ['description', 'enabled', 'id', 'remote_ids'] + IDENTITY_PROVIDER_LIST_HEADERS = ['ID', 'Enabled', 'Description'] @classmethod def setUpClass(cls): diff --git a/functional/tests/identity/v3/test_idp.py b/functional/tests/identity/v3/test_idp.py index 6a07f15..3d6739d 100644 --- a/functional/tests/identity/v3/test_idp.py +++ b/functional/tests/identity/v3/test_idp.py @@ -11,6 +11,7 @@ # under the License. from functional.tests.identity.v3 import test_identity +from tempest_lib.common.utils import data_utils class IdentityProviderTests(test_identity.IdentityTests): @@ -18,3 +19,36 @@ class IdentityProviderTests(test_identity.IdentityTests): def test_idp_create(self): self._create_dummy_idp() + + def test_idp_delete(self): + identity_provider = self._create_dummy_idp(add_clean_up=False) + raw_output = self.openstack('identity provider delete %s' + % identity_provider) + self.assertEqual(0, len(raw_output)) + + def test_idp_show(self): + identity_provider = self._create_dummy_idp(add_clean_up=True) + raw_output = self.openstack('identity provider show %s' + % identity_provider) + items = self.parse_show(raw_output) + self.assert_show_fields(items, self.IDENTITY_PROVIDER_FIELDS) + + def test_idp_list(self): + self._create_dummy_idp(add_clean_up=True) + raw_output = self.openstack('identity provider list') + items = self.parse_listing(raw_output) + self.assert_table_structure(items, self.IDENTITY_PROVIDER_LIST_HEADERS) + + def test_idp_set(self): + identity_provider = self._create_dummy_idp(add_clean_up=True) + new_remoteid = data_utils.rand_name('newRemoteId') + raw_output = self.openstack('identity provider set ' + '%(identity-provider)s ' + '--remote-id %(remote-id)s ' + % {'identity-provider': identity_provider, + 'remote-id': new_remoteid}) + self.assertEqual(0, len(raw_output)) + raw_output = self.openstack('identity provider show %s' + % identity_provider) + updated_value = self.parse_show_as_object(raw_output) + self.assertIn(new_remoteid, updated_value['remote_ids']) diff --git a/functional/tests/image/v1/test_image.py b/functional/tests/image/v1/test_image.py index 9f6ddcc..17c0c3d 100644 --- a/functional/tests/image/v1/test_image.py +++ b/functional/tests/image/v1/test_image.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import os import uuid from functional.common import test @@ -25,6 +26,7 @@ class ImageTests(test.TestCase): @classmethod def setUpClass(cls): + os.environ['OS_IMAGE_API_VERSION'] = '1' opts = cls.get_show_opts(cls.FIELDS) raw_output = cls.openstack('image create ' + cls.NAME + opts) expected = cls.NAME + '\n' diff --git a/openstackclient/api/auth.py b/openstackclient/api/auth.py index 820b4ec..66272e4 100644 --- a/openstackclient/api/auth.py +++ b/openstackclient/api/auth.py @@ -185,7 +185,7 @@ def build_auth_plugins_option_parser(parser): metavar='<auth-type>', dest='auth_type', default=utils.env('OS_AUTH_TYPE'), - help='Select an auhentication type. Available types: ' + + help='Select an authentication type. Available types: ' + ', '.join(available_plugins) + '. Default: selected based on --os-username/--os-token' + ' (Env: OS_AUTH_TYPE)', diff --git a/openstackclient/common/configuration.py b/openstackclient/common/configuration.py index 83df73e..ac2792d 100644 --- a/openstackclient/common/configuration.py +++ b/openstackclient/common/configuration.py @@ -18,6 +18,8 @@ import logging from cliff import show import six +from openstackclient.common import utils + REDACTED = "<redacted>" @@ -44,8 +46,8 @@ class ShowConfiguration(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) info = self.app.client_manager.get_configuration() for key, value in six.iteritems(info.pop('auth', {})): diff --git a/openstackclient/common/context.py b/openstackclient/common/context.py new file mode 100644 index 0000000..6d1aec1 --- /dev/null +++ b/openstackclient/common/context.py @@ -0,0 +1,170 @@ +# 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. +# + +"""Application logging""" + +import logging +import sys +import warnings + + +def log_level_from_options(options): + # if --debug, --quiet or --verbose is not specified, + # the default logging level is warning + log_level = logging.WARNING + if options.verbose_level == 0: + # --quiet + log_level = logging.ERROR + elif options.verbose_level == 2: + # One --verbose + log_level = logging.INFO + elif options.verbose_level >= 3: + # Two or more --verbose + log_level = logging.DEBUG + return log_level + + +def log_level_from_config(config): + # Check the command line option + verbose_level = config.get('verbose_level') + if config.get('debug', False): + verbose_level = 3 + if verbose_level == 0: + verbose_level = 'error' + elif verbose_level == 1: + # If a command line option has not been specified, check the + # configuration file + verbose_level = config.get('log_level', 'warning') + elif verbose_level == 2: + verbose_level = 'info' + else: + verbose_level = 'debug' + + log_level = { + 'critical': logging.CRITICAL, + 'error': logging.ERROR, + 'warning': logging.WARNING, + 'info': logging.INFO, + 'debug': logging.DEBUG, + }.get(verbose_level, logging.WARNING) + return log_level + + +def set_warning_filter(log_level): + if log_level == logging.ERROR: + warnings.simplefilter("ignore") + elif log_level == logging.WARNING: + warnings.simplefilter("ignore") + elif log_level == logging.INFO: + warnings.simplefilter("once") + + +class _FileFormatter(logging.Formatter): + """Customize the logging format for logging handler""" + _LOG_MESSAGE_BEGIN = ( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s ') + _LOG_MESSAGE_CONTEXT = '[%(cloud)s %(username)s %(project)s] ' + _LOG_MESSAGE_END = '%(message)s' + _LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S' + + def __init__(self, options=None, config=None, **kwargs): + context = {} + if options: + context = { + 'cloud': getattr(options, 'cloud', ''), + 'project': getattr(options, 'os_project_name', ''), + 'username': getattr(options, 'username', ''), + } + elif config: + context = { + 'cloud': config.config.get('cloud', ''), + 'project': config.auth.get('project_name', ''), + 'username': config.auth.get('username', ''), + } + if context: + self.fmt = (self._LOG_MESSAGE_BEGIN + + (self._LOG_MESSAGE_CONTEXT % context) + + self._LOG_MESSAGE_END) + else: + self.fmt = self._LOG_MESSAGE_BEGIN + self._LOG_MESSAGE_END + logging.Formatter.__init__(self, self.fmt, self._LOG_DATE_FORMAT) + + +class LogConfigurator(object): + + _CONSOLE_MESSAGE_FORMAT = '%(message)s' + + def __init__(self, options): + self.root_logger = logging.getLogger('') + self.root_logger.setLevel(logging.DEBUG) + + # Force verbose_level 3 on --debug + self.dump_trace = False + if options.debug: + options.verbose_level = 3 + self.dump_trace = True + + # Always send higher-level messages to the console via stderr + self.console_logger = logging.StreamHandler(sys.stderr) + log_level = log_level_from_options(options) + self.console_logger.setLevel(log_level) + formatter = logging.Formatter(self._CONSOLE_MESSAGE_FORMAT) + self.console_logger.setFormatter(formatter) + self.root_logger.addHandler(self.console_logger) + + # Set the warning filter now + set_warning_filter(log_level) + + # Set up logging to a file + self.file_logger = None + log_file = options.log_file + if log_file: + self.file_logger = logging.FileHandler(filename=log_file) + self.file_logger.setFormatter(_FileFormatter(options=options)) + self.file_logger.setLevel(log_level) + self.root_logger.addHandler(self.file_logger) + + # Requests logs some stuff at INFO that we don't want + # unless we have DEBUG + requests_log = logging.getLogger("requests") + + # Other modules we don't want DEBUG output for + cliff_log = logging.getLogger('cliff') + stevedore_log = logging.getLogger('stevedore') + iso8601_log = logging.getLogger("iso8601") + + if options.debug: + # --debug forces traceback + requests_log.setLevel(logging.DEBUG) + else: + requests_log.setLevel(logging.ERROR) + + cliff_log.setLevel(logging.ERROR) + stevedore_log.setLevel(logging.ERROR) + iso8601_log.setLevel(logging.ERROR) + + def configure(self, cloud_config): + log_level = log_level_from_config(cloud_config.config) + set_warning_filter(log_level) + self.dump_trace = cloud_config.config.get('debug', self.dump_trace) + self.console_logger.setLevel(log_level) + + log_file = cloud_config.config.get('log_file', None) + if log_file: + if not self.file_logger: + self.file_logger = logging.FileHandler(filename=log_file) + formatter = _FileFormatter(cloud_config=cloud_config) + self.file_logger.setFormatter(formatter) + self.file_logger.setFormatter(_FileFormatter(config=cloud_config)) + self.file_logger.setLevel(log_level) + self.root_logger.addHandler(self.file_logger) diff --git a/openstackclient/common/limits.py b/openstackclient/common/limits.py index 4abcf16..582f70c 100644 --- a/openstackclient/common/limits.py +++ b/openstackclient/common/limits.py @@ -31,7 +31,7 @@ class ShowLimits(lister.Lister): def get_parser(self, prog_name): parser = super(ShowLimits, self).get_parser(prog_name) - type_group = parser.add_mutually_exclusive_group() + type_group = parser.add_mutually_exclusive_group(required=True) type_group.add_argument( "--absolute", dest="is_absolute", @@ -64,8 +64,8 @@ class ShowLimits(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume diff --git a/openstackclient/common/module.py b/openstackclient/common/module.py index 356cdca..f0ed23b 100644 --- a/openstackclient/common/module.py +++ b/openstackclient/common/module.py @@ -22,6 +22,8 @@ import sys from cliff import lister from cliff import show +from openstackclient.common import utils + class ListCommand(lister.Lister): """List recognized commands by group""" @@ -29,8 +31,8 @@ class ListCommand(lister.Lister): auth_required = False log = logging.getLogger(__name__ + '.ListCommand') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) cm = self.app.command_manager groups = cm.get_command_groups() @@ -54,8 +56,8 @@ class ListModule(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) data = {} # Get module versions diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index e79fd7e..e092fef 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -23,6 +23,8 @@ import sys from cliff import command from cliff import show +from openstackclient.common import utils + # List the quota items, map the internal argument name to the option # name that the user sees. @@ -89,8 +91,8 @@ class SetQuota(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume @@ -103,8 +105,7 @@ class SetQuota(command.Command): volume_kwargs = {} for k, v in VOLUME_QUOTAS.items(): - # TODO(jiaxi): Should use k or v needs discuss - value = getattr(parsed_args, v, None) + value = getattr(parsed_args, k, None) if value is not None: if parsed_args.volume_type: k = k + '_%s' % parsed_args.volume_type @@ -188,8 +189,8 @@ class ShowQuota(show.ShowOne): else: return {} + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py index 2f8419f..b6726bf 100644 --- a/openstackclient/common/utils.py +++ b/openstackclient/common/utils.py @@ -26,6 +26,29 @@ from oslo_utils import importutils from openstackclient.common import exceptions +def log_method(log, level=logging.DEBUG): + """Logs a method and its arguments when entered.""" + + def decorator(func): + func_name = func.__name__ + + @six.wraps(func) + def wrapper(self, *args, **kwargs): + if log.isEnabledFor(level): + pretty_args = [] + if args: + pretty_args.extend(str(a) for a in args) + if kwargs: + pretty_args.extend( + "%s=%s" % (k, v) for k, v in six.iteritems(kwargs)) + log.log(level, "%s(%s)", func_name, ", ".join(pretty_args)) + return func(self, *args, **kwargs) + + return wrapper + + return decorator + + def find_resource(manager, name_or_id, **kwargs): """Helper for the _find_* methods. diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py index 9dda32d..8ac5f32 100644 --- a/openstackclient/compute/client.py +++ b/openstackclient/compute/client.py @@ -15,6 +15,7 @@ import logging +from openstackclient.common import exceptions from openstackclient.common import utils LOG = logging.getLogger(__name__) @@ -26,6 +27,9 @@ API_VERSIONS = { "2": "novaclient.client", } +# Save the microversion if in use +_compute_api_version = None + def make_client(instance): """Returns a compute service client.""" @@ -38,10 +42,12 @@ def make_client(instance): except ImportError: from novaclient.v1_1.contrib import list_extensions - compute_client = nova_client.get_client_class( - instance._api_version[API_NAME], - ) - LOG.debug('Instantiating compute client: %s', compute_client) + if _compute_api_version is not None: + version = _compute_api_version + else: + version = instance._api_version[API_NAME] + + LOG.debug('Instantiating compute client for V%s' % version) # Set client http_log_debug to True if verbosity level is high enough http_log_debug = utils.get_effective_log_level() <= logging.DEBUG @@ -51,7 +57,8 @@ def make_client(instance): # Remember interface only if it is set kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface) - client = compute_client( + client = nova_client.Client( + version, session=instance.session, extensions=extensions, http_log_debug=http_log_debug, @@ -73,3 +80,45 @@ def build_option_parser(parser): DEFAULT_API_VERSION + ' (Env: OS_COMPUTE_API_VERSION)') return parser + + +def check_api_version(check_version): + """Validate version supplied by user + + Returns: + * True if version is OK + * False if the version has not been checked and the previous plugin + check should be performed + * throws an exception if the version is no good + + TODO(dtroyer): make the exception thrown a version-related one + """ + + # Defer client imports until we actually need them + try: + from novaclient import api_versions + except ImportError: + # Retain previous behaviour + return False + + import novaclient + + global _compute_api_version + + # Copy some logic from novaclient 2.27.0 for basic version detection + # NOTE(dtroyer): This is only enough to resume operations using API + # version 2.0 or any valid version supplied by the user. + _compute_api_version = api_versions.get_api_version(check_version) + + if _compute_api_version > api_versions.APIVersion("2.0"): + if not _compute_api_version.matches( + novaclient.API_MIN_VERSION, + novaclient.API_MAX_VERSION, + ): + raise exceptions.CommandError( + "versions supported by client: %s - %s" % ( + novaclient.API_MIN_VERSION.get_string(), + novaclient.API_MAX_VERSION.get_string(), + ), + ) + return True diff --git a/openstackclient/compute/v2/aggregate.py b/openstackclient/compute/v2/aggregate.py index 84ed5c7..a1ba618 100644 --- a/openstackclient/compute/v2/aggregate.py +++ b/openstackclient/compute/v2/aggregate.py @@ -123,8 +123,8 @@ class DeleteAggregate(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute data = utils.find_resource( @@ -256,8 +256,8 @@ class SetAggregate(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute aggregate = utils.find_resource( @@ -303,8 +303,8 @@ class ShowAggregate(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute data = utils.find_resource( diff --git a/openstackclient/compute/v2/availability_zone.py b/openstackclient/compute/v2/availability_zone.py index 648c0ee..0fe6c73 100644 --- a/openstackclient/compute/v2/availability_zone.py +++ b/openstackclient/compute/v2/availability_zone.py @@ -73,8 +73,8 @@ class ListAvailabilityZone(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('Zone Name', 'Zone Status', diff --git a/openstackclient/compute/v2/console.py b/openstackclient/compute/v2/console.py index 082a3a0..bb0747b 100644 --- a/openstackclient/compute/v2/console.py +++ b/openstackclient/compute/v2/console.py @@ -47,8 +47,8 @@ class ShowConsoleLog(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -103,8 +103,8 @@ class ShowConsoleURL(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, diff --git a/openstackclient/compute/v2/floatingip.py b/openstackclient/compute/v2/floatingip.py index 658f0d5..c557c24 100644 --- a/openstackclient/compute/v2/floatingip.py +++ b/openstackclient/compute/v2/floatingip.py @@ -69,8 +69,8 @@ class CreateFloatingIP(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute floating_ip = compute_client.floating_ips.create(parsed_args.pool) @@ -93,8 +93,8 @@ class DeleteFloatingIP(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute floating_ip = utils.find_resource( @@ -111,8 +111,8 @@ class ListFloatingIP(lister.Lister): log = logging.getLogger(__name__ + '.ListFloatingIP') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute columns = ('ID', 'Pool', 'IP', 'Fixed IP', 'Instance ID') diff --git a/openstackclient/compute/v2/floatingippool.py b/openstackclient/compute/v2/floatingippool.py index db1c9f0..cc48555 100644 --- a/openstackclient/compute/v2/floatingippool.py +++ b/openstackclient/compute/v2/floatingippool.py @@ -27,8 +27,8 @@ class ListFloatingIPPool(lister.Lister): log = logging.getLogger(__name__ + '.ListFloatingIPPool') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute columns = ('Name',) diff --git a/openstackclient/compute/v2/keypair.py b/openstackclient/compute/v2/keypair.py index edf25f8..5c627c5 100644 --- a/openstackclient/compute/v2/keypair.py +++ b/openstackclient/compute/v2/keypair.py @@ -47,8 +47,8 @@ class CreateKeypair(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute public_key = parsed_args.public_key @@ -93,8 +93,8 @@ class DeleteKeypair(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute compute_client.keypairs.delete(parsed_args.name) return @@ -140,8 +140,8 @@ class ShowKeypair(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute keypair = utils.find_resource(compute_client.keypairs, parsed_args.name) diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py index 3dc9bae..3dd0c49 100644 --- a/openstackclient/compute/v2/security_group.py +++ b/openstackclient/compute/v2/security_group.py @@ -50,10 +50,10 @@ def _xform_security_group_rule(sgroup): info['ip_range'] = info['ip_range']['cidr'] else: info['ip_range'] = '' - if info['ip_protocol'] == 'icmp': - info['port_range'] = '' - elif info['ip_protocol'] is None: + if info['ip_protocol'] is None: info['ip_protocol'] = '' + elif info['ip_protocol'].lower() == 'icmp': + info['port_range'] = '' return info @@ -107,8 +107,8 @@ class DeleteSecurityGroup(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute data = utils.find_resource( @@ -199,8 +199,8 @@ class SetSecurityGroup(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute data = utils.find_resource( @@ -240,8 +240,8 @@ class ShowSecurityGroup(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute info = {} @@ -307,7 +307,10 @@ class CreateSecurityGroupRule(show.ShowOne): compute_client.security_groups, parsed_args.group, ) - from_port, to_port = parsed_args.dst_port + if parsed_args.proto.lower() == 'icmp': + from_port, to_port = -1, -1 + else: + from_port, to_port = parsed_args.dst_port data = compute_client.security_group_rules.create( group.id, parsed_args.proto, @@ -334,8 +337,8 @@ class DeleteSecurityGroupRule(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute compute_client.security_group_rules.delete(parsed_args.rule) diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 4efef97..661ce84 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -36,6 +36,7 @@ from openstackclient.common import exceptions from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.i18n import _ # noqa +from openstackclient.identity import common as identity_common from openstackclient.network import common @@ -107,14 +108,20 @@ def _prep_server_detail(compute_client, server): image_info = info.get('image', {}) if image_info: image_id = image_info.get('id', '') - image = utils.find_resource(compute_client.images, image_id) - info['image'] = "%s (%s)" % (image.name, image_id) + try: + image = utils.find_resource(compute_client.images, image_id) + info['image'] = "%s (%s)" % (image.name, image_id) + except Exception: + info['image'] = image_id # Convert the flavor blob to a name flavor_info = info.get('flavor', {}) flavor_id = flavor_info.get('id', '') - flavor = utils.find_resource(compute_client.flavors, flavor_id) - info['flavor'] = "%s (%s)" % (flavor.name, flavor_id) + try: + flavor = utils.find_resource(compute_client.flavors, flavor_id) + info['flavor'] = "%s (%s)" % (flavor.name, flavor_id) + except Exception: + info['flavor'] = flavor_id # NOTE(dtroyer): novaclient splits these into separate entries... # Format addresses in a useful way @@ -355,8 +362,8 @@ class CreateServer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume @@ -553,8 +560,8 @@ class CreateServerImage(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute image_client = self.app.client_manager.image server = utils.find_resource( @@ -612,8 +619,8 @@ class DeleteServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute for server in parsed_args.servers: server_obj = utils.find_resource( @@ -694,6 +701,17 @@ class ListServer(lister.Lister): help=_('Include all projects (admin only)'), ) parser.add_argument( + '--project', + metavar='<project>', + help="Search by project (admin only) (name or ID)") + identity_common.add_project_domain_option_to_parser(parser) + parser.add_argument( + '--user', + metavar='<user>', + help=_('Search by user (admin only) (name or ID)'), + ) + identity_common.add_user_domain_option_to_parser(parser) + parser.add_argument( '--long', action='store_true', default=False, @@ -701,9 +719,28 @@ class ListServer(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute + identity_client = self.app.client_manager.identity + + project_id = None + if parsed_args.project: + project_id = identity_common.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain, + ).id + parsed_args.all_projects = True + + user_id = None + if parsed_args.user: + user_id = identity_common.find_project( + identity_client, + parsed_args.user, + parsed_args.user_domain, + ).id + search_opts = { 'reservation_id': parsed_args.reservation_id, 'ip': parsed_args.ip, @@ -714,7 +751,9 @@ class ListServer(lister.Lister): 'flavor': parsed_args.flavor, 'image': parsed_args.image, 'host': parsed_args.host, + 'tenant_id': project_id, 'all_tenants': parsed_args.all_projects, + 'user_id': user_id, } self.log.debug('search options: %s', search_opts) @@ -772,8 +811,8 @@ class LockServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -845,8 +884,8 @@ class MigrateServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute @@ -889,8 +928,8 @@ class PauseServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -935,8 +974,8 @@ class RebootServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, parsed_args.server) @@ -984,8 +1023,8 @@ class RebuildServer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute # Lookup parsed_args.image @@ -1100,8 +1139,8 @@ class RescueServer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute _, body = utils.find_resource( @@ -1146,8 +1185,8 @@ class ResizeServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -1191,8 +1230,8 @@ class ResumeServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -1232,8 +1271,8 @@ class SetServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -1280,8 +1319,8 @@ class ShowServer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource(compute_client.servers, parsed_args.server) @@ -1403,8 +1442,8 @@ class SshServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -1458,8 +1497,8 @@ class SuspendServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -1482,8 +1521,8 @@ class UnlockServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -1506,8 +1545,8 @@ class UnpauseServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -1530,8 +1569,8 @@ class UnrescueServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute utils.find_resource( @@ -1562,8 +1601,8 @@ class UnsetServer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, diff --git a/openstackclient/identity/v2_0/catalog.py b/openstackclient/identity/v2_0/catalog.py index e166c85..9bc2755 100644 --- a/openstackclient/identity/v2_0/catalog.py +++ b/openstackclient/identity/v2_0/catalog.py @@ -42,8 +42,8 @@ class ListCatalog(lister.Lister): log = logging.getLogger(__name__ + '.ListCatalog') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) # This is ugly because if auth hasn't happened yet we need # to trigger it here. @@ -76,8 +76,8 @@ class ShowCatalog(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) # This is ugly because if auth hasn't happened yet we need # to trigger it here. diff --git a/openstackclient/identity/v2_0/ec2creds.py b/openstackclient/identity/v2_0/ec2creds.py index 348479a..a7730ce 100644 --- a/openstackclient/identity/v2_0/ec2creds.py +++ b/openstackclient/identity/v2_0/ec2creds.py @@ -52,8 +52,8 @@ class CreateEC2Creds(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.project: @@ -105,8 +105,8 @@ class DeleteEC2Creds(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.user: @@ -135,8 +135,8 @@ class ListEC2Creds(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.user: @@ -178,8 +178,8 @@ class ShowEC2Creds(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.user: diff --git a/openstackclient/identity/v2_0/endpoint.py b/openstackclient/identity/v2_0/endpoint.py index 370a931..1744cc7 100644 --- a/openstackclient/identity/v2_0/endpoint.py +++ b/openstackclient/identity/v2_0/endpoint.py @@ -62,8 +62,8 @@ class CreateEndpoint(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) endpoint = identity_client.endpoints.create( @@ -93,8 +93,8 @@ class DeleteEndpoint(command.Command): help=_('Endpoint ID to delete')) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_client.endpoints.delete(parsed_args.endpoint) return @@ -115,8 +115,8 @@ class ListEndpoint(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.long: columns = ('ID', 'Region', 'Service Name', 'Service Type', @@ -150,8 +150,8 @@ class ShowEndpoint(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity data = identity_client.endpoints.list() match = None diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py index d01807a..97a95f2 100644 --- a/openstackclient/identity/v2_0/project.py +++ b/openstackclient/identity/v2_0/project.py @@ -70,8 +70,8 @@ class CreateProject(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity enabled = True @@ -118,8 +118,8 @@ class DeleteProject(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity for project in parsed_args.projects: @@ -146,8 +146,8 @@ class ListProject(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('ID', 'Name', 'Description', 'Enabled') else: @@ -202,8 +202,8 @@ class SetProject(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if (not parsed_args.name @@ -253,8 +253,8 @@ class ShowProject(show.ShowOne): help=_('Project to display (name or ID)')) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity info = {} diff --git a/openstackclient/identity/v2_0/role.py b/openstackclient/identity/v2_0/role.py index 3167f50..e98f8cb 100644 --- a/openstackclient/identity/v2_0/role.py +++ b/openstackclient/identity/v2_0/role.py @@ -54,8 +54,8 @@ class AddRole(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity role = utils.find_resource(identity_client.roles, parsed_args.role) project = utils.find_resource( @@ -93,8 +93,8 @@ class CreateRole(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity try: role = identity_client.roles.create(parsed_args.role_name) @@ -128,8 +128,8 @@ class DeleteRole(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity for role in parsed_args.roles: @@ -160,8 +160,8 @@ class ListRole(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref @@ -242,8 +242,8 @@ class ListUserRole(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref @@ -316,8 +316,8 @@ class RemoveRole(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity role = utils.find_resource(identity_client.roles, parsed_args.role) project = utils.find_resource( @@ -345,8 +345,8 @@ class ShowRole(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity role = utils.find_resource(identity_client.roles, parsed_args.role) diff --git a/openstackclient/identity/v2_0/service.py b/openstackclient/identity/v2_0/service.py index f863023..c9d4844 100644 --- a/openstackclient/identity/v2_0/service.py +++ b/openstackclient/identity/v2_0/service.py @@ -59,8 +59,8 @@ class CreateService(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity type_or_name = parsed_args.type_or_name @@ -106,8 +106,8 @@ class DeleteService(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) identity_client.services.delete(service.id) @@ -129,8 +129,8 @@ class ListService(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('ID', 'Name', 'Type', 'Description') @@ -163,8 +163,8 @@ class ShowService(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref diff --git a/openstackclient/identity/v2_0/token.py b/openstackclient/identity/v2_0/token.py index c8b003e..5fed58e 100644 --- a/openstackclient/identity/v2_0/token.py +++ b/openstackclient/identity/v2_0/token.py @@ -21,6 +21,7 @@ import six from cliff import command from cliff import show +from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -33,8 +34,8 @@ class IssueToken(show.ShowOne): parser = super(IssueToken, self).get_parser(prog_name) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) token = self.app.client_manager.auth_ref.service_catalog.get_token() token['project_id'] = token.pop('tenant_id') diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py index 500aeec..76902e6 100644 --- a/openstackclient/identity/v2_0/user.py +++ b/openstackclient/identity/v2_0/user.py @@ -78,8 +78,8 @@ class CreateUser(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.project: @@ -142,8 +142,8 @@ class DeleteUser(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity for user in parsed_args.users: @@ -174,8 +174,8 @@ class ListUser(lister.Lister): help=_('List additional fields in output')) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity def _format_project(project): @@ -296,8 +296,8 @@ class SetUser(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.password_prompt: @@ -362,8 +362,8 @@ class ShowUser(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity info = {} diff --git a/openstackclient/identity/v3/catalog.py b/openstackclient/identity/v3/catalog.py index 1899f25..76f7da5 100644 --- a/openstackclient/identity/v3/catalog.py +++ b/openstackclient/identity/v3/catalog.py @@ -39,8 +39,8 @@ class ListCatalog(lister.Lister): log = logging.getLogger(__name__ + '.ListCatalog') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) # This is ugly because if auth hasn't happened yet we need # to trigger it here. @@ -73,8 +73,8 @@ class ShowCatalog(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) # This is ugly because if auth hasn't happened yet we need # to trigger it here. diff --git a/openstackclient/identity/v3/consumer.py b/openstackclient/identity/v3/consumer.py index ffbd510..0a6ade6 100644 --- a/openstackclient/identity/v3/consumer.py +++ b/openstackclient/identity/v3/consumer.py @@ -40,8 +40,8 @@ class CreateConsumer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity consumer = identity_client.oauth1.consumers.create( parsed_args.description @@ -64,8 +64,8 @@ class DeleteConsumer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity consumer = utils.find_resource( identity_client.oauth1.consumers, parsed_args.consumer) @@ -78,8 +78,8 @@ class ListConsumer(lister.Lister): log = logging.getLogger(__name__ + '.ListConsumer') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) columns = ('ID', 'Description') data = self.app.client_manager.identity.oauth1.consumers.list() return (columns, @@ -108,8 +108,8 @@ class SetConsumer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity consumer = utils.find_resource( identity_client.oauth1.consumers, parsed_args.consumer) @@ -140,8 +140,8 @@ class ShowConsumer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity consumer = utils.find_resource( identity_client.oauth1.consumers, parsed_args.consumer) diff --git a/openstackclient/identity/v3/credential.py b/openstackclient/identity/v3/credential.py index dacbc9a..dbd73e2 100644 --- a/openstackclient/identity/v3/credential.py +++ b/openstackclient/identity/v3/credential.py @@ -57,8 +57,8 @@ class CreateCredential(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity user_id = utils.find_resource(identity_client.users, parsed_args.user).id @@ -91,8 +91,8 @@ class DeleteCredential(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_client.credentials.delete(parsed_args.credential) return @@ -103,8 +103,8 @@ class ListCredential(lister.Lister): log = logging.getLogger(__name__ + '.ListCredential') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) columns = ('ID', 'Type', 'User ID', 'Blob', 'Project ID') column_headers = ('ID', 'Type', 'User ID', 'Data', 'Project ID') data = self.app.client_manager.identity.credentials.list() @@ -150,8 +150,8 @@ class SetCredential(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity kwargs = {} if parsed_args.user: @@ -189,8 +189,8 @@ class ShowCredential(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity credential = utils.find_resource(identity_client.credentials, parsed_args.credential) diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py index 38f99a9..aec530a 100644 --- a/openstackclient/identity/v3/domain.py +++ b/openstackclient/identity/v3/domain.py @@ -63,8 +63,8 @@ class CreateDomain(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity enabled = True @@ -103,8 +103,8 @@ class DeleteDomain(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = utils.find_resource(identity_client.domains, parsed_args.domain) @@ -117,8 +117,8 @@ class ListDomain(lister.Lister): log = logging.getLogger(__name__ + '.ListDomain') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) columns = ('ID', 'Name', 'Enabled', 'Description') data = self.app.client_manager.identity.domains.list() return (columns, @@ -163,8 +163,8 @@ class SetDomain(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = utils.find_resource(identity_client.domains, parsed_args.domain) @@ -200,8 +200,8 @@ class ShowDomain(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = utils.find_resource(identity_client.domains, parsed_args.domain) diff --git a/openstackclient/identity/v3/ec2creds.py b/openstackclient/identity/v3/ec2creds.py index 0331463..a12ee25 100644 --- a/openstackclient/identity/v3/ec2creds.py +++ b/openstackclient/identity/v3/ec2creds.py @@ -79,8 +79,8 @@ class CreateEC2Creds(show.ShowOne): common.add_project_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity client_manager = self.app.client_manager user = _determine_ec2_user(parsed_args, client_manager) @@ -136,8 +136,8 @@ class DeleteEC2Creds(command.Command): common.add_user_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', 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) @@ -158,8 +158,8 @@ class ListEC2Creds(lister.Lister): common.add_user_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) client_manager = self.app.client_manager user = _determine_ec2_user(parsed_args, client_manager) @@ -194,8 +194,8 @@ class ShowEC2Creds(show.ShowOne): common.add_user_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) client_manager = self.app.client_manager user = _determine_ec2_user(parsed_args, client_manager) creds = client_manager.identity.ec2.get(user, parsed_args.access_key) diff --git a/openstackclient/identity/v3/endpoint.py b/openstackclient/identity/v3/endpoint.py index 52db5ac..3d1c6f5 100644 --- a/openstackclient/identity/v3/endpoint.py +++ b/openstackclient/identity/v3/endpoint.py @@ -78,8 +78,8 @@ class CreateEndpoint(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) @@ -113,8 +113,8 @@ class DeleteEndpoint(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity endpoint_id = utils.find_resource(identity_client.endpoints, parsed_args.endpoint).id @@ -147,8 +147,8 @@ class ListEndpoint(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity columns = ('ID', 'Region', 'Service Name', 'Service Type', 'Enabled', 'Interface', 'URL') @@ -221,8 +221,8 @@ class SetEndpoint(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity endpoint = utils.find_resource(identity_client.endpoints, parsed_args.endpoint) @@ -270,8 +270,8 @@ class ShowEndpoint(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity endpoint = utils.find_resource(identity_client.endpoints, parsed_args.endpoint) diff --git a/openstackclient/identity/v3/federation_protocol.py b/openstackclient/identity/v3/federation_protocol.py index 57e8255..20877fc 100644 --- a/openstackclient/identity/v3/federation_protocol.py +++ b/openstackclient/identity/v3/federation_protocol.py @@ -50,8 +50,8 @@ class CreateProtocol(show.ShowOne): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity protocol = identity_client.federation.protocols.create( protocol_id=parsed_args.federation_protocol, @@ -88,8 +88,8 @@ class DeleteProtocol(command.Command): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_client.federation.protocols.delete( parsed_args.identity_provider, parsed_args.federation_protocol) diff --git a/openstackclient/identity/v3/group.py b/openstackclient/identity/v3/group.py index d659f71..8297506 100644 --- a/openstackclient/identity/v3/group.py +++ b/openstackclient/identity/v3/group.py @@ -50,8 +50,8 @@ class AddUserToGroup(command.Command): common.add_user_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity user_id = common.find_user(identity_client, @@ -92,8 +92,8 @@ class CheckUserInGroup(command.Command): common.add_user_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity user_id = common.find_user(identity_client, @@ -142,8 +142,8 @@ class CreateGroup(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = None @@ -188,8 +188,8 @@ class DeleteGroup(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity for group in parsed_args.groups: @@ -226,8 +226,8 @@ class ListGroup(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = None @@ -284,8 +284,8 @@ class RemoveUserFromGroup(command.Command): common.add_user_domain_option_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity user_id = common.find_user(identity_client, @@ -331,8 +331,8 @@ class SetGroup(command.Command): help='New group description') return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity group = common.find_group(identity_client, parsed_args.group, parsed_args.domain) @@ -368,8 +368,8 @@ class ShowGroup(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity group = common.find_group(identity_client, diff --git a/openstackclient/identity/v3/identity_provider.py b/openstackclient/identity/v3/identity_provider.py index 8096580..27982a9 100644 --- a/openstackclient/identity/v3/identity_provider.py +++ b/openstackclient/identity/v3/identity_provider.py @@ -70,8 +70,8 @@ class CreateIdentityProvider(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.remote_id_file: file_content = utils.read_blob_file_contents( @@ -105,8 +105,8 @@ class DeleteIdentityProvider(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_client.federation.identity_providers.delete( parsed_args.identity_provider) @@ -118,8 +118,8 @@ class ListIdentityProvider(lister.Lister): log = logging.getLogger(__name__ + '.ListIdentityProvider') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) columns = ('ID', 'Enabled', 'Description') identity_client = self.app.client_manager.identity data = identity_client.federation.identity_providers.list() @@ -169,8 +169,8 @@ class SetIdentityProvider(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) federation_client = self.app.client_manager.identity.federation # Basic argument checking @@ -218,8 +218,8 @@ class ShowIdentityProvider(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_provider = utils.find_resource( identity_client.federation.identity_providers, diff --git a/openstackclient/identity/v3/policy.py b/openstackclient/identity/v3/policy.py index 8293542..9da9486 100644 --- a/openstackclient/identity/v3/policy.py +++ b/openstackclient/identity/v3/policy.py @@ -47,8 +47,8 @@ class CreatePolicy(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) blob = utils.read_blob_file_contents(parsed_args.rules) identity_client = self.app.client_manager.identity @@ -75,8 +75,8 @@ class DeletePolicy(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_client.policies.delete(parsed_args.policy) return @@ -97,8 +97,8 @@ class ListPolicy(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('ID', 'Type', 'Blob') column_headers = ('ID', 'Type', 'Rules') @@ -137,8 +137,8 @@ class SetPolicy(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity blob = None @@ -172,8 +172,8 @@ class ShowPolicy(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity policy = utils.find_resource(identity_client.policies, parsed_args.policy) diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py index 8185d65..96d7f97 100644 --- a/openstackclient/identity/v3/project.py +++ b/openstackclient/identity/v3/project.py @@ -81,8 +81,8 @@ class CreateProject(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = None @@ -146,8 +146,8 @@ class DeleteProject(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = None @@ -190,8 +190,8 @@ class ListProject(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.long: columns = ('ID', 'Name', 'Domain ID', 'Description', 'Enabled') @@ -271,8 +271,8 @@ class SetProject(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if (not parsed_args.name @@ -337,8 +337,8 @@ class ShowProject(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.domain: diff --git a/openstackclient/identity/v3/region.py b/openstackclient/identity/v3/region.py index 5cb51fc..eb4c084 100644 --- a/openstackclient/identity/v3/region.py +++ b/openstackclient/identity/v3/region.py @@ -56,8 +56,8 @@ class CreateRegion(show.ShowOne): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity region = identity_client.regions.create( @@ -87,8 +87,8 @@ class DeleteRegion(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity identity_client.regions.delete(parsed_args.region) @@ -109,8 +109,8 @@ class ListRegion(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity kwargs = {} @@ -157,8 +157,8 @@ class SetRegion(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if (not parsed_args.url @@ -192,8 +192,8 @@ class ShowRegion(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity region = utils.find_resource(identity_client.regions, diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py index 9243639..c72de47 100644 --- a/openstackclient/identity/v3/role.py +++ b/openstackclient/identity/v3/role.py @@ -39,7 +39,7 @@ def _add_identity_and_resource_options_to_parser(parser): domain_or_project.add_argument( '--project', metavar='<project>', - help='Include `<project>` (name or ID)', + help='Include <project> (name or ID)', ) user_or_group = parser.add_mutually_exclusive_group() user_or_group.add_argument( @@ -122,8 +122,8 @@ class AddRole(command.Command): _add_identity_and_resource_options_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if (not parsed_args.user and not parsed_args.domain @@ -166,8 +166,8 @@ class CreateRole(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity try: @@ -199,8 +199,8 @@ class DeleteRole(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity for role in parsed_args.roles: @@ -325,8 +325,8 @@ class RemoveRole(command.Command): _add_identity_and_resource_options_to_parser(parser) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if (not parsed_args.user and not parsed_args.domain @@ -368,8 +368,8 @@ class SetRole(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if not parsed_args.name: @@ -398,8 +398,8 @@ class ShowRole(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity role = utils.find_resource( diff --git a/openstackclient/identity/v3/service.py b/openstackclient/identity/v3/service.py index d63a953..85081aa 100644 --- a/openstackclient/identity/v3/service.py +++ b/openstackclient/identity/v3/service.py @@ -61,8 +61,8 @@ class CreateService(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity enabled = True @@ -94,8 +94,8 @@ class DeleteService(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) @@ -119,8 +119,8 @@ class ListService(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('ID', 'Name', 'Type', 'Description', 'Enabled') @@ -173,8 +173,8 @@ class SetService(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if (not parsed_args.name @@ -219,8 +219,8 @@ class ShowService(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) diff --git a/openstackclient/identity/v3/service_provider.py b/openstackclient/identity/v3/service_provider.py index 78f96b6..838ad4a 100644 --- a/openstackclient/identity/v3/service_provider.py +++ b/openstackclient/identity/v3/service_provider.py @@ -73,8 +73,8 @@ class CreateServiceProvider(show.ShowOne): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) service_client = self.app.client_manager.identity sp = service_client.federation.service_providers.create( id=parsed_args.service_provider_id, @@ -101,8 +101,8 @@ class DeleteServiceProvider(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) service_client = self.app.client_manager.identity service_client.federation.service_providers.delete( parsed_args.service_provider) @@ -114,8 +114,8 @@ class ListServiceProvider(lister.Lister): log = logging.getLogger(__name__ + '.ListServiceProvider') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) service_client = self.app.client_manager.identity data = service_client.federation.service_providers.list() @@ -168,8 +168,8 @@ class SetServiceProvider(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) federation_client = self.app.client_manager.identity.federation enabled = None @@ -207,8 +207,8 @@ class ShowServiceProvider(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) service_client = self.app.client_manager.identity service_provider = utils.find_resource( service_client.federation.service_providers, diff --git a/openstackclient/identity/v3/token.py b/openstackclient/identity/v3/token.py index 7000b62..cd3dc79 100644 --- a/openstackclient/identity/v3/token.py +++ b/openstackclient/identity/v3/token.py @@ -182,8 +182,8 @@ class IssueToken(show.ShowOne): parser = super(IssueToken, self).get_parser(prog_name) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) token = self.app.client_manager.auth_ref.service_catalog.get_token() if 'tenant_id' in token: token['project_id'] = token.pop('tenant_id') diff --git a/openstackclient/identity/v3/unscoped_saml.py b/openstackclient/identity/v3/unscoped_saml.py index fddac68..e659e75 100644 --- a/openstackclient/identity/v3/unscoped_saml.py +++ b/openstackclient/identity/v3/unscoped_saml.py @@ -49,8 +49,8 @@ class ListAccessibleDomains(lister.Lister): log = logging.getLogger(__name__ + '.ListAccessibleDomains') @auth_with_unscoped_saml + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) columns = ('ID', 'Enabled', 'Name', 'Description') identity_client = self.app.client_manager.identity data = identity_client.federation.domains.list() @@ -67,8 +67,8 @@ class ListAccessibleProjects(lister.Lister): log = logging.getLogger(__name__ + '.ListAccessibleProjects') @auth_with_unscoped_saml + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) columns = ('ID', 'Domain ID', 'Enabled', 'Name') identity_client = self.app.client_manager.identity data = identity_client.federation.projects.list() diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py index 459707d..0e89454 100644 --- a/openstackclient/identity/v3/user.py +++ b/openstackclient/identity/v3/user.py @@ -91,8 +91,8 @@ class CreateUser(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity project_id = None @@ -155,8 +155,8 @@ class DeleteUser(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = None @@ -205,8 +205,8 @@ class ListUser(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity domain = None @@ -214,13 +214,11 @@ class ListUser(lister.Lister): domain = common.find_domain(identity_client, parsed_args.domain).id + group = None if parsed_args.group: - group = utils.find_resource( - identity_client.groups, - parsed_args.group, - ).id - else: - group = None + group = common.find_group(identity_client, + parsed_args.group, + parsed_args.domain).id if parsed_args.project: if domain is not None: @@ -336,8 +334,8 @@ class SetUser(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.password_prompt: @@ -396,8 +394,8 @@ class SetPasswordUser(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity current_password = utils.get_password( @@ -430,8 +428,8 @@ class ShowUser(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity if parsed_args.domain: diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 4c019db..3e1c824 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -22,14 +22,51 @@ import six from cliff import command from cliff import lister from cliff import show - from glanceclient.common import utils as gc_utils + from openstackclient.api import utils as api_utils +from openstackclient.common import exceptions from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.identity import common +DEFAULT_CONTAINER_FORMAT = 'bare' +DEFAULT_DISK_FORMAT = 'raw' + + +def _format_image(image): + """Format an image to make it more consistent with OSC operations. """ + + info = {} + properties = {} + + # the only fields we're not including is "links", "tags" and the properties + fields_to_show = ['status', 'name', 'container_format', 'created_at', + 'size', 'disk_format', 'updated_at', 'visibility', + 'min_disk', 'protected', 'id', 'file', 'checksum', + 'owner', 'virtual_size', 'min_ram', 'schema'] + + # split out the usual key and the properties which are top-level + for key in six.iterkeys(image): + if key in fields_to_show: + info[key] = image.get(key) + elif key == 'tags': + continue # handle this later + else: + properties[key] = image.get(key) + + # format the tags if they are there + if image.get('tags'): + info['tags'] = utils.format_list(image.get('tags')) + + # add properties back into the dictionary as a top-level key + if properties: + info['properties'] = utils.format_dict(properties) + + return info + + class AddProjectToImage(show.ShowOne): """Associate project with image""" @@ -72,6 +109,187 @@ class AddProjectToImage(show.ShowOne): return zip(*sorted(six.iteritems(image_member._info))) +class CreateImage(show.ShowOne): + """Create/upload an image""" + + log = logging.getLogger(__name__ + ".CreateImage") + deadopts = ('owner', 'size', 'location', 'copy-from', 'checksum', 'store') + + def get_parser(self, prog_name): + parser = super(CreateImage, self).get_parser(prog_name) + # TODO(mordred): add --volume and --force parameters and support + # TODO(bunting): There are additional arguments that v1 supported + # that v2 either doesn't support or supports weirdly. + # --checksum - could be faked clientside perhaps? + # --owner - could be set as an update after the put? + # --location - maybe location add? + # --size - passing image size is actually broken in python-glanceclient + # --copy-from - does not exist in v2 + # --store - does not exits in v2 + parser.add_argument( + "name", + metavar="<image-name>", + help="New image name", + ) + parser.add_argument( + "--id", + metavar="<id>", + help="Image ID to reserve", + ) + parser.add_argument( + "--container-format", + default=DEFAULT_CONTAINER_FORMAT, + metavar="<container-format>", + help="Image container format " + "(default: %s)" % DEFAULT_CONTAINER_FORMAT, + ) + parser.add_argument( + "--disk-format", + default=DEFAULT_DISK_FORMAT, + metavar="<disk-format>", + help="Image disk format " + "(default: %s)" % DEFAULT_DISK_FORMAT, + ) + parser.add_argument( + "--min-disk", + metavar="<disk-gb>", + type=int, + help="Minimum disk size needed to boot image, in gigabytes", + ) + parser.add_argument( + "--min-ram", + metavar="<ram-mb>", + type=int, + help="Minimum RAM size needed to boot image, in megabytes", + ) + parser.add_argument( + "--file", + metavar="<file>", + help="Upload image from local file", + ) + protected_group = parser.add_mutually_exclusive_group() + protected_group.add_argument( + "--protected", + action="store_true", + help="Prevent image from being deleted", + ) + protected_group.add_argument( + "--unprotected", + action="store_true", + help="Allow image to be deleted (default)", + ) + public_group = parser.add_mutually_exclusive_group() + public_group.add_argument( + "--public", + action="store_true", + help="Image is accessible to the public", + ) + public_group.add_argument( + "--private", + action="store_true", + help="Image is inaccessible to the public (default)", + ) + parser.add_argument( + "--property", + dest="properties", + metavar="<key=value>", + action=parseractions.KeyValueAction, + help="Set a property on this image " + "(repeat option to set multiple properties)", + ) + parser.add_argument( + "--tag", + dest="tags", + metavar="<tag>", + action='append', + help="Set a tag on this image " + "(repeat option to set multiple tags)", + ) + for deadopt in self.deadopts: + parser.add_argument( + "--%s" % deadopt, + metavar="<%s>" % deadopt, + dest=deadopt.replace('-', '_'), + help=argparse.SUPPRESS + ) + return parser + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)", parsed_args) + image_client = self.app.client_manager.image + + for deadopt in self.deadopts: + if getattr(parsed_args, deadopt.replace('-', '_'), None): + raise exceptions.CommandError( + "ERROR: --%s was given, which is an Image v1 option" + " that is no longer supported in Image v2" % deadopt) + + # Build an attribute dict from the parsed args, only include + # attributes that were actually set on the command line + kwargs = {} + copy_attrs = ('name', 'id', + 'container_format', 'disk_format', + 'min_disk', 'min_ram', + 'tags') + for attr in copy_attrs: + if attr in parsed_args: + val = getattr(parsed_args, attr, None) + if val: + # Only include a value in kwargs for attributes that + # are actually present on the command line + kwargs[attr] = val + # properties should get flattened into the general kwargs + if getattr(parsed_args, 'properties', None): + for k, v in six.iteritems(parsed_args.properties): + kwargs[k] = str(v) + # Handle exclusive booleans with care + # Avoid including attributes in kwargs if an option is not + # present on the command line. These exclusive booleans are not + # a single value for the pair of options because the default must be + # to do nothing when no options are present as opposed to always + # setting a default. + if parsed_args.protected: + kwargs['protected'] = True + if parsed_args.unprotected: + kwargs['protected'] = False + if parsed_args.public: + kwargs['visibility'] = 'public' + if parsed_args.private: + kwargs['visibility'] = 'private' + + # open the file first to ensure any failures are handled before the + # image is created + fp = gc_utils.get_data_file(parsed_args) + + if fp is None and parsed_args.file: + self.log.warning("Failed to get an image file.") + return {}, {} + + image = image_client.images.create(**kwargs) + + if fp is not None: + with fp: + try: + image_client.images.upload(image.id, fp) + except Exception as e: + # 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 + # the Image already exists and should be left alone. + try: + if 'id' not in kwargs: + image_client.images.delete(image.id) + except Exception: + pass # we don't care about this one + raise e # now, throw the upload exception again + + # update the image after the data has been uploaded + image = image_client.images.get(image.id) + + info = _format_image(image) + return zip(*sorted(six.iteritems(info))) + + class DeleteImage(command.Command): """Delete image(s)""" @@ -229,7 +447,7 @@ class ListImage(lister.Lister): s, columns, formatters={ - 'tags': utils.format_dict, + 'tags': utils.format_list, }, ) for s in data) ) @@ -327,8 +545,7 @@ class ShowImage(show.ShowOne): parsed_args.image, ) - info = {} - info.update(image) + info = _format_image(image) return zip(*sorted(six.iteritems(info))) diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py index bc4fdec..49173de 100644 --- a/openstackclient/object/v1/container.py +++ b/openstackclient/object/v1/container.py @@ -41,8 +41,8 @@ class CreateContainer(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) results = [] for container in parsed_args.containers: @@ -74,8 +74,8 @@ class DeleteContainer(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) for container in parsed_args.containers: self.app.client_manager.object_store.container_delete( @@ -125,8 +125,8 @@ class ListContainer(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('Name', 'Bytes', 'Count') @@ -192,8 +192,8 @@ class ShowContainer(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) data = self.app.client_manager.object_store.container_show( container=parsed_args.container, diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py index 752d784..c90f031 100644 --- a/openstackclient/object/v1/object.py +++ b/openstackclient/object/v1/object.py @@ -46,8 +46,8 @@ class CreateObject(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) results = [] for obj in parsed_args.objects: @@ -85,8 +85,8 @@ class DeleteObject(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) for obj in parsed_args.objects: self.app.client_manager.object_store.object_delete( @@ -147,8 +147,8 @@ class ListObject(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ( @@ -240,8 +240,8 @@ class ShowObject(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) data = self.app.client_manager.object_store.object_show( container=parsed_args.container, diff --git a/openstackclient/shell.py b/openstackclient/shell.py index a8b5ac4..d3a7d8a 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -20,7 +20,6 @@ import getpass import logging import sys import traceback -import warnings from cliff import app from cliff import command @@ -30,6 +29,7 @@ from cliff import help import openstackclient from openstackclient.common import clientmanager from openstackclient.common import commandmanager +from openstackclient.common import context from openstackclient.common import exceptions as exc from openstackclient.common import timing from openstackclient.common import utils @@ -94,62 +94,19 @@ class OpenStackShell(app.App): self.verify = True self.client_manager = None + self.command_options = None def configure_logging(self): - """Configure logging for the app - - Cliff sets some defaults we don't want so re-work it a bit - """ - - if self.options.debug: - # --debug forces verbose_level 3 - # Set this here so cliff.app.configure_logging() can work - self.options.verbose_level = 3 - - super(OpenStackShell, self).configure_logging() - root_logger = logging.getLogger('') - - # Set logging to the requested level - if self.options.verbose_level == 0: - # --quiet - root_logger.setLevel(logging.ERROR) - warnings.simplefilter("ignore") - elif self.options.verbose_level == 1: - # This is the default case, no --debug, --verbose or --quiet - root_logger.setLevel(logging.WARNING) - warnings.simplefilter("ignore") - elif self.options.verbose_level == 2: - # One --verbose - root_logger.setLevel(logging.INFO) - warnings.simplefilter("once") - elif self.options.verbose_level >= 3: - # Two or more --verbose - root_logger.setLevel(logging.DEBUG) - - # Requests logs some stuff at INFO that we don't want - # unless we have DEBUG - requests_log = logging.getLogger("requests") - - # Other modules we don't want DEBUG output for - cliff_log = logging.getLogger('cliff') - stevedore_log = logging.getLogger('stevedore') - iso8601_log = logging.getLogger("iso8601") - - if self.options.debug: - # --debug forces traceback - self.dump_stack_trace = True - requests_log.setLevel(logging.DEBUG) - else: - self.dump_stack_trace = False - requests_log.setLevel(logging.ERROR) - - cliff_log.setLevel(logging.ERROR) - stevedore_log.setLevel(logging.ERROR) - iso8601_log.setLevel(logging.ERROR) + """Configure logging for the app.""" + self.log_configurator = context.LogConfigurator(self.options) + self.dump_stack_trace = self.log_configurator.dump_trace def run(self, argv): + ret_val = 1 + self.command_options = argv try: - return super(OpenStackShell, self).run(argv) + ret_val = super(OpenStackShell, self).run(argv) + return ret_val except Exception as e: if not logging.getLogger('').handlers: logging.basicConfig() @@ -157,7 +114,11 @@ class OpenStackShell(app.App): self.log.error(traceback.format_exc(e)) else: self.log.error('Exception raised: ' + str(e)) - return 1 + + return ret_val + + finally: + self.log.info("END return value: %s", ret_val) def build_option_parser(self, description, version): parser = super(OpenStackShell, self).build_option_parser( @@ -236,14 +197,15 @@ class OpenStackShell(app.App): # Parent __init__ parses argv into self.options super(OpenStackShell, self).initialize_app(argv) + self.log.info("START with options: %s", self.command_options) + self.log.debug("options: %s", self.options) # Set the default plugin to token_endpoint if url and token are given if (self.options.url and self.options.token): # Use service token authentication auth_type = 'token_endpoint' else: - auth_type = 'osc_password' - self.log.debug("options: %s", self.options) + auth_type = 'password' project_id = getattr(self.options, 'project_id', None) project_name = getattr(self.options, 'project_name', None) @@ -266,14 +228,20 @@ class OpenStackShell(app.App): # Ignore the default value of interface. Only if it is set later # will it be used. cc = cloud_config.OpenStackConfig( - override_defaults={'interface': None, - 'auth_type': auth_type, }) - self.log.debug("defaults: %s", cc.defaults) + override_defaults={ + 'interface': None, + 'auth_type': auth_type, + }, + ) self.cloud = cc.get_one_cloud( cloud=self.options.cloud, argparse=self.options, ) + + self.log_configurator.configure(self.cloud) + self.dump_stack_trace = self.log_configurator.dump_trace + self.log.debug("defaults: %s", cc.defaults) self.log.debug("cloud cfg: %s", self.cloud.config) # Set up client TLS @@ -304,11 +272,23 @@ class OpenStackShell(app.App): if version_opt: api = mod.API_NAME self.api_version[api] = version_opt - if version_opt not in mod.API_VERSIONS: - self.log.warning( - "The %s version <%s> is not in supported versions <%s>" - % (api, version_opt, - ', '.join(mod.API_VERSIONS.keys()))) + + # Add a plugin interface to let the module validate the version + # requested by the user + skip_old_check = False + mod_check_api_version = getattr(mod, 'check_api_version', None) + if mod_check_api_version: + # this throws an exception if invalid + skip_old_check = mod_check_api_version(version_opt) + + mod_versions = getattr(mod, 'API_VERSIONS', None) + if not skip_old_check and mod_versions: + if version_opt not in mod_versions: + self.log.warning( + "%s version %s is not in supported versions %s" + % (api, version_opt, + ', '.join(mod.API_VERSIONS.keys()))) + # Command groups deal only with major versions version = '.v' + version_opt.replace('.', '_').split('_')[0] cmd_group = 'openstack.' + api.replace('-', '_') + version diff --git a/openstackclient/tests/common/test_context.py b/openstackclient/tests/common/test_context.py new file mode 100644 index 0000000..55e4285 --- /dev/null +++ b/openstackclient/tests/common/test_context.py @@ -0,0 +1,202 @@ +# 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. +# + +import logging +import mock + +from openstackclient.common import context +from openstackclient.tests import utils + + +class TestContext(utils.TestCase): + + def test_log_level_from_options(self): + opts = mock.Mock() + opts.verbose_level = 0 + self.assertEqual(logging.ERROR, context.log_level_from_options(opts)) + opts.verbose_level = 1 + self.assertEqual(logging.WARNING, context.log_level_from_options(opts)) + opts.verbose_level = 2 + self.assertEqual(logging.INFO, context.log_level_from_options(opts)) + opts.verbose_level = 3 + self.assertEqual(logging.DEBUG, context.log_level_from_options(opts)) + + def test_log_level_from_config(self): + cfg = {'verbose_level': 0} + self.assertEqual(logging.ERROR, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1} + self.assertEqual(logging.WARNING, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 2} + self.assertEqual(logging.INFO, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 3} + self.assertEqual(logging.DEBUG, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'critical'} + self.assertEqual(logging.CRITICAL, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'error'} + self.assertEqual(logging.ERROR, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'warning'} + self.assertEqual(logging.WARNING, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'info'} + self.assertEqual(logging.INFO, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'debug'} + self.assertEqual(logging.DEBUG, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'bogus'} + self.assertEqual(logging.WARNING, context.log_level_from_config(cfg)) + cfg = {'verbose_level': 1, 'log_level': 'info', 'debug': True} + self.assertEqual(logging.DEBUG, context.log_level_from_config(cfg)) + + @mock.patch('warnings.simplefilter') + def test_set_warning_filter(self, simplefilter): + context.set_warning_filter(logging.ERROR) + simplefilter.assert_called_with("ignore") + context.set_warning_filter(logging.WARNING) + simplefilter.assert_called_with("ignore") + context.set_warning_filter(logging.INFO) + simplefilter.assert_called_with("once") + + +class TestFileFormatter(utils.TestCase): + def test_nothing(self): + formatter = context._FileFormatter() + self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s %(message)s'), formatter.fmt) + + def test_options(self): + class Opts(object): + cloud = 'cloudy' + os_project_name = 'projecty' + username = 'usernamey' + options = Opts() + formatter = context._FileFormatter(options=options) + self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s [cloudy usernamey projecty] %(message)s'), + formatter.fmt) + + def test_config(self): + config = mock.Mock() + config.config = {'cloud': 'cloudy'} + config.auth = {'project_name': 'projecty', 'username': 'usernamey'} + formatter = context._FileFormatter(config=config) + self.assertEqual(('%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' + '%(name)s [cloudy usernamey projecty] %(message)s'), + formatter.fmt) + + +class TestLogConfigurator(utils.TestCase): + def setUp(self): + super(TestLogConfigurator, self).setUp() + self.options = mock.Mock() + self.options.verbose_level = 1 + self.options.log_file = None + self.options.debug = False + self.root_logger = mock.Mock() + self.root_logger.setLevel = mock.Mock() + self.root_logger.addHandler = mock.Mock() + self.requests_log = mock.Mock() + self.requests_log.setLevel = mock.Mock() + self.cliff_log = mock.Mock() + self.cliff_log.setLevel = mock.Mock() + self.stevedore_log = mock.Mock() + self.stevedore_log.setLevel = mock.Mock() + self.iso8601_log = mock.Mock() + self.iso8601_log.setLevel = mock.Mock() + self.loggers = [ + self.root_logger, + self.requests_log, + self.cliff_log, + self.stevedore_log, + self.iso8601_log] + + @mock.patch('logging.StreamHandler') + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.context.set_warning_filter') + def test_init(self, warning_filter, getLogger, handle): + getLogger.side_effect = self.loggers + console_logger = mock.Mock() + console_logger.setFormatter = mock.Mock() + console_logger.setLevel = mock.Mock() + handle.return_value = console_logger + + configurator = context.LogConfigurator(self.options) + + getLogger.assert_called_with('iso8601') # last call + warning_filter.assert_called_with(logging.WARNING) + self.root_logger.setLevel.assert_called_with(logging.DEBUG) + self.root_logger.addHandler.assert_called_with(console_logger) + self.requests_log.setLevel.assert_called_with(logging.ERROR) + self.cliff_log.setLevel.assert_called_with(logging.ERROR) + self.stevedore_log.setLevel.assert_called_with(logging.ERROR) + self.iso8601_log.setLevel.assert_called_with(logging.ERROR) + self.assertEqual(False, configurator.dump_trace) + + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.context.set_warning_filter') + def test_init_no_debug(self, warning_filter, getLogger): + getLogger.side_effect = self.loggers + self.options.debug = True + + configurator = context.LogConfigurator(self.options) + + warning_filter.assert_called_with(logging.DEBUG) + self.requests_log.setLevel.assert_called_with(logging.DEBUG) + self.assertEqual(True, configurator.dump_trace) + + @mock.patch('logging.FileHandler') + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.context.set_warning_filter') + @mock.patch('openstackclient.common.context._FileFormatter') + def test_init_log_file(self, formatter, warning_filter, getLogger, handle): + getLogger.side_effect = self.loggers + self.options.log_file = '/tmp/log_file' + file_logger = mock.Mock() + file_logger.setFormatter = mock.Mock() + file_logger.setLevel = mock.Mock() + handle.return_value = file_logger + mock_formatter = mock.Mock() + formatter.return_value = mock_formatter + + context.LogConfigurator(self.options) + + handle.assert_called_with(filename=self.options.log_file) + self.root_logger.addHandler.assert_called_with(file_logger) + file_logger.setFormatter.assert_called_with(mock_formatter) + file_logger.setLevel.assert_called_with(logging.WARNING) + + @mock.patch('logging.FileHandler') + @mock.patch('logging.getLogger') + @mock.patch('openstackclient.common.context.set_warning_filter') + @mock.patch('openstackclient.common.context._FileFormatter') + def test_configure(self, formatter, warning_filter, getLogger, handle): + getLogger.side_effect = self.loggers + configurator = context.LogConfigurator(self.options) + cloud_config = mock.Mock() + config_log = '/tmp/config_log' + cloud_config.config = { + 'log_file': config_log, + 'verbose_level': 1, + 'log_level': 'info'} + file_logger = mock.Mock() + file_logger.setFormatter = mock.Mock() + file_logger.setLevel = mock.Mock() + handle.return_value = file_logger + mock_formatter = mock.Mock() + formatter.return_value = mock_formatter + + configurator.configure(cloud_config) + + warning_filter.assert_called_with(logging.INFO) + handle.assert_called_with(filename=config_log) + self.root_logger.addHandler.assert_called_with(file_logger) + file_logger.setFormatter.assert_called_with(mock_formatter) + file_logger.setLevel.assert_called_with(logging.INFO) + self.assertEqual(False, configurator.dump_trace) diff --git a/openstackclient/tests/common/test_quota.py b/openstackclient/tests/common/test_quota.py index f0013e4..b6ad156 100644 --- a/openstackclient/tests/common/test_quota.py +++ b/openstackclient/tests/common/test_quota.py @@ -12,6 +12,8 @@ import copy +import mock + from openstackclient.common import quota from openstackclient.tests.compute.v2 import fakes as compute_fakes from openstackclient.tests import fakes @@ -38,6 +40,11 @@ class TestQuota(compute_fakes.TestComputev2): super(TestQuota, self).setUp() self.quotas_mock = self.app.client_manager.compute.quotas self.quotas_mock.reset_mock() + volume_mock = mock.Mock() + volume_mock.quotas = mock.Mock() + self.app.client_manager.volume = volume_mock + self.volume_quotas_mock = volume_mock.quotas + self.volume_quotas_mock.reset_mock() class TestQuotaSet(TestQuota): @@ -57,6 +64,18 @@ class TestQuotaSet(TestQuota): loaded=True, ) + self.volume_quotas_mock.find.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.volume_quotas_mock.update.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + self.cmd = quota.SetQuota(self.app, None) def test_quota_set(self): @@ -87,3 +106,29 @@ class TestQuotaSet(TestQuota): } self.quotas_mock.update.assert_called_with('project_test', **kwargs) + + def test_quota_set_volume(self): + arglist = [ + '--gigabytes', str(compute_fakes.floating_ip_num), + '--snapshots', str(compute_fakes.fix_ip_num), + '--volumes', str(compute_fakes.injected_file_num), + compute_fakes.project_name, + ] + verifylist = [ + ('gigabytes', compute_fakes.floating_ip_num), + ('snapshots', compute_fakes.fix_ip_num), + ('volumes', compute_fakes.injected_file_num), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + kwargs = { + 'gigabytes': compute_fakes.floating_ip_num, + 'snapshots': compute_fakes.fix_ip_num, + 'volumes': compute_fakes.injected_file_num, + } + + self.volume_quotas_mock.update.assert_called_with('project_test', + **kwargs) diff --git a/openstackclient/tests/compute/v2/test_security_group_rule.py b/openstackclient/tests/compute/v2/test_security_group_rule.py new file mode 100644 index 0000000..9516f8d --- /dev/null +++ b/openstackclient/tests/compute/v2/test_security_group_rule.py @@ -0,0 +1,338 @@ +# 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. +# + +import copy +import mock + +from openstackclient.compute.v2 import security_group +from openstackclient.tests.compute.v2 import fakes as compute_fakes +from openstackclient.tests import fakes +from openstackclient.tests.identity.v2_0 import fakes as identity_fakes + + +security_group_id = '11' +security_group_name = 'wide-open' +security_group_description = 'nothing but net' + +security_group_rule_id = '1' + +SECURITY_GROUP = { + 'id': security_group_id, + 'name': security_group_name, + 'description': security_group_description, + 'tenant_id': identity_fakes.project_id, +} + +SECURITY_GROUP_RULE = { + 'id': security_group_rule_id, + 'group': {}, + 'ip_protocol': 'tcp', + 'ip_range': '0.0.0.0/0', + 'parent_group_id': security_group_id, + 'from_port': 0, + 'to_port': 0, +} + +SECURITY_GROUP_RULE_ICMP = { + 'id': security_group_rule_id, + 'group': {}, + 'ip_protocol': 'icmp', + 'ip_range': '0.0.0.0/0', + 'parent_group_id': security_group_id, + 'from_port': -1, + 'to_port': -1, +} + + +class FakeSecurityGroupRuleResource(fakes.FakeResource): + + def get_keys(self): + return {'property': 'value'} + + +class TestSecurityGroupRule(compute_fakes.TestComputev2): + + def setUp(self): + super(TestSecurityGroupRule, self).setUp() + + self.secgroups_mock = mock.Mock() + self.secgroups_mock.resource_class = fakes.FakeResource(None, {}) + self.app.client_manager.compute.security_groups = self.secgroups_mock + self.secgroups_mock.reset_mock() + + self.sg_rules_mock = mock.Mock() + self.sg_rules_mock.resource_class = fakes.FakeResource(None, {}) + self.app.client_manager.compute.security_group_rules = \ + self.sg_rules_mock + self.sg_rules_mock.reset_mock() + + +class TestSecurityGroupRuleCreate(TestSecurityGroupRule): + + def setUp(self): + super(TestSecurityGroupRuleCreate, self).setUp() + + self.secgroups_mock.get.return_value = FakeSecurityGroupRuleResource( + None, + copy.deepcopy(SECURITY_GROUP), + loaded=True, + ) + + # Get the command object to test + self.cmd = security_group.CreateSecurityGroupRule(self.app, None) + + def test_security_group_rule_create_no_options(self): + self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( + None, + copy.deepcopy(SECURITY_GROUP_RULE), + loaded=True, + ) + + arglist = [ + security_group_name, + ] + verifylist = [ + ('group', security_group_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.sg_rules_mock.create.assert_called_with( + security_group_id, + 'tcp', + 0, + 0, + '0.0.0.0/0', + ) + + collist = ( + 'group', + 'id', + 'ip_protocol', + 'ip_range', + 'parent_group_id', + 'port_range', + ) + self.assertEqual(collist, columns) + datalist = ( + {}, + security_group_rule_id, + 'tcp', + '', + security_group_id, + '0:0', + ) + self.assertEqual(datalist, data) + + def test_security_group_rule_create_ftp(self): + sg_rule = copy.deepcopy(SECURITY_GROUP_RULE) + sg_rule['from_port'] = 20 + sg_rule['to_port'] = 21 + self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( + None, + sg_rule, + loaded=True, + ) + + arglist = [ + security_group_name, + '--dst-port', '20:21', + ] + verifylist = [ + ('group', security_group_name), + ('dst_port', (20, 21)), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.sg_rules_mock.create.assert_called_with( + security_group_id, + 'tcp', + 20, + 21, + '0.0.0.0/0', + ) + + collist = ( + 'group', + 'id', + 'ip_protocol', + 'ip_range', + 'parent_group_id', + 'port_range', + ) + self.assertEqual(collist, columns) + datalist = ( + {}, + security_group_rule_id, + 'tcp', + '', + security_group_id, + '20:21', + ) + self.assertEqual(datalist, data) + + def test_security_group_rule_create_ssh(self): + sg_rule = copy.deepcopy(SECURITY_GROUP_RULE) + sg_rule['from_port'] = 22 + sg_rule['to_port'] = 22 + self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( + None, + sg_rule, + loaded=True, + ) + + arglist = [ + security_group_name, + '--dst-port', '22', + ] + verifylist = [ + ('group', security_group_name), + ('dst_port', (22, 22)), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.sg_rules_mock.create.assert_called_with( + security_group_id, + 'tcp', + 22, + 22, + '0.0.0.0/0', + ) + + collist = ( + 'group', + 'id', + 'ip_protocol', + 'ip_range', + 'parent_group_id', + 'port_range', + ) + self.assertEqual(collist, columns) + datalist = ( + {}, + security_group_rule_id, + 'tcp', + '', + security_group_id, + '22:22', + ) + self.assertEqual(datalist, data) + + def test_security_group_rule_create_udp(self): + sg_rule = copy.deepcopy(SECURITY_GROUP_RULE) + sg_rule['ip_protocol'] = 'udp' + self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( + None, + sg_rule, + loaded=True, + ) + + arglist = [ + security_group_name, + '--proto', 'udp', + ] + verifylist = [ + ('group', security_group_name), + ('proto', 'udp'), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.sg_rules_mock.create.assert_called_with( + security_group_id, + 'udp', + 0, + 0, + '0.0.0.0/0', + ) + + collist = ( + 'group', + 'id', + 'ip_protocol', + 'ip_range', + 'parent_group_id', + 'port_range', + ) + self.assertEqual(collist, columns) + datalist = ( + {}, + security_group_rule_id, + 'udp', + '', + security_group_id, + '0:0', + ) + self.assertEqual(datalist, data) + + def test_security_group_rule_create_icmp(self): + self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( + None, + copy.deepcopy(SECURITY_GROUP_RULE_ICMP), + loaded=True, + ) + + arglist = [ + security_group_name, + '--proto', 'ICMP', + ] + verifylist = [ + ('group', security_group_name), + ('proto', 'ICMP'), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.sg_rules_mock.create.assert_called_with( + security_group_id, + 'ICMP', + -1, + -1, + '0.0.0.0/0', + ) + + collist = ( + 'group', + 'id', + 'ip_protocol', + 'ip_range', + 'parent_group_id', + 'port_range', + ) + self.assertEqual(collist, columns) + datalist = ( + {}, + security_group_rule_id, + 'icmp', + '', + security_group_id, + '', + ) + self.assertEqual(datalist, data) diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index bfb9476..bb720d7 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -19,6 +19,7 @@ import mock import warlock from glanceclient.v2 import schemas +from openstackclient.common import exceptions from openstackclient.image.v2 import image from openstackclient.tests import fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes @@ -41,6 +42,191 @@ class TestImage(image_fakes.TestImagev2): self.domain_mock.reset_mock() +class TestImageCreate(TestImage): + + def setUp(self): + super(TestImageCreate, self).setUp() + + self.images_mock.create.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + # This is the return value for utils.find_resource() + self.images_mock.get.return_value = copy.deepcopy(image_fakes.IMAGE) + self.images_mock.update.return_value = fakes.FakeResource( + None, + copy.deepcopy(image_fakes.IMAGE), + loaded=True, + ) + + # Get the command object to test + self.cmd = image.CreateImage(self.app, None) + + def test_image_reserve_no_options(self): + mock_exception = { + 'find.side_effect': exceptions.CommandError('x'), + } + self.images_mock.configure_mock(**mock_exception) + arglist = [ + image_fakes.image_name, + ] + verifylist = [ + ('container_format', image.DEFAULT_CONTAINER_FORMAT), + ('disk_format', image.DEFAULT_DISK_FORMAT), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ImageManager.create(name=, **) + self.images_mock.create.assert_called_with( + name=image_fakes.image_name, + container_format=image.DEFAULT_CONTAINER_FORMAT, + disk_format=image.DEFAULT_DISK_FORMAT, + ) + + # Verify update() was not called, if it was show the args + self.assertEqual(self.images_mock.update.call_args_list, []) + + self.images_mock.upload.assert_called_with( + mock.ANY, mock.ANY, + ) + + self.assertEqual(image_fakes.IMAGE_columns, columns) + self.assertEqual(image_fakes.IMAGE_data, data) + + @mock.patch('glanceclient.common.utils.get_data_file', name='Open') + def test_image_reserve_options(self, mock_open): + mock_file = mock.MagicMock(name='File') + mock_open.return_value = mock_file + mock_open.read.return_value = None + mock_exception = { + 'find.side_effect': exceptions.CommandError('x'), + } + self.images_mock.configure_mock(**mock_exception) + arglist = [ + '--container-format', 'ovf', + '--disk-format', 'fs', + '--min-disk', '10', + '--min-ram', '4', + '--protected', + '--private', + image_fakes.image_name, + ] + verifylist = [ + ('container_format', 'ovf'), + ('disk_format', 'fs'), + ('min_disk', 10), + ('min_ram', 4), + ('protected', True), + ('unprotected', False), + ('public', False), + ('private', True), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ImageManager.create(name=, **) + self.images_mock.create.assert_called_with( + name=image_fakes.image_name, + container_format='ovf', + disk_format='fs', + min_disk=10, + min_ram=4, + protected=True, + visibility='private', + ) + + # Verify update() was not called, if it was show the args + self.assertEqual(self.images_mock.update.call_args_list, []) + + self.images_mock.upload.assert_called_with( + mock.ANY, mock.ANY, + ) + + self.assertEqual(image_fakes.IMAGE_columns, columns) + self.assertEqual(image_fakes.IMAGE_data, data) + + @mock.patch('glanceclient.common.utils.get_data_file', name='Open') + def test_image_create_file(self, mock_open): + mock_file = mock.MagicMock(name='File') + mock_open.return_value = mock_file + mock_open.read.return_value = image_fakes.IMAGE_data + mock_exception = { + 'find.side_effect': exceptions.CommandError('x'), + } + self.images_mock.configure_mock(**mock_exception) + + arglist = [ + '--file', 'filer', + '--unprotected', + '--public', + '--property', 'Alpha=1', + '--property', 'Beta=2', + '--tag', 'awesome', + '--tag', 'better', + image_fakes.image_name, + ] + verifylist = [ + ('file', 'filer'), + ('protected', False), + ('unprotected', True), + ('public', True), + ('private', False), + ('properties', {'Alpha': '1', 'Beta': '2'}), + ('tags', ['awesome', 'better']), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ImageManager.create(name=, **) + self.images_mock.create.assert_called_with( + name=image_fakes.image_name, + container_format=image.DEFAULT_CONTAINER_FORMAT, + disk_format=image.DEFAULT_DISK_FORMAT, + protected=False, + visibility='public', + Alpha='1', + Beta='2', + tags=['awesome', 'better'], + ) + + # Verify update() was not called, if it was show the args + self.assertEqual(self.images_mock.update.call_args_list, []) + + self.images_mock.upload.assert_called_with( + mock.ANY, mock.ANY, + ) + + self.assertEqual(image_fakes.IMAGE_columns, columns) + self.assertEqual(image_fakes.IMAGE_data, data) + + def test_image_dead_options(self): + + arglist = [ + '--owner', 'nobody', + image_fakes.image_name, + ] + verifylist = [ + ('owner', 'nobody'), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, parsed_args) + + class TestAddProjectToImage(TestImage): def setUp(self): diff --git a/openstackclient/tests/test_shell.py b/openstackclient/tests/test_shell.py index 0e0cc50..c548d89 100644 --- a/openstackclient/tests/test_shell.py +++ b/openstackclient/tests/test_shell.py @@ -77,6 +77,8 @@ CLOUD_2 = { 'username': 'zaphod', }, 'region_name': 'occ-cloud', + 'log_file': '/tmp/test_log_file', + 'log_level': 'debug', } } } diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py index 0d8c202..7b7758a 100644 --- a/openstackclient/tests/volume/v2/fakes.py +++ b/openstackclient/tests/volume/v2/fakes.py @@ -15,14 +15,15 @@ import copy import mock -from openstackclient.tests.compute.v2 import fakes as compute_fakes from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes from openstackclient.tests.image.v2 import fakes as image_fakes from openstackclient.tests import utils -volume_attachment_server = copy.deepcopy(compute_fakes.SERVER) -volume_attachment_server['device'] = 'device' +volume_attachment_server = { + 'device': '/dev/ice', + 'server_id': '1233', +} volume_id = "ce26708d-a7f8-4b4b-9861-4a80256615a6" volume_name = "fake_volume" diff --git a/openstackclient/tests/volume/v2/test_volume.py b/openstackclient/tests/volume/v2/test_volume.py index 348ae37..b15fd02 100644 --- a/openstackclient/tests/volume/v2/test_volume.py +++ b/openstackclient/tests/volume/v2/test_volume.py @@ -548,7 +548,7 @@ class TestVolumeList(TestVolume): ] self.assertEqual(collist, columns) - server = volume_fakes.volume_attachment_server['id'] + server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) datalist = (( @@ -583,7 +583,7 @@ class TestVolumeList(TestVolume): ] self.assertEqual(collist, columns) - server = volume_fakes.volume_attachment_server['id'] + server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) datalist = (( @@ -618,7 +618,7 @@ class TestVolumeList(TestVolume): ) self.assertEqual(collist, tuple(columns)) - server = volume_fakes.volume_attachment_server['id'] + server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) @@ -654,7 +654,7 @@ class TestVolumeList(TestVolume): ) self.assertEqual(collist, tuple(columns)) - server = volume_fakes.volume_attachment_server['id'] + server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) datalist = (( @@ -693,7 +693,7 @@ class TestVolumeList(TestVolume): ] self.assertEqual(collist, columns) - server = volume_fakes.volume_attachment_server['id'] + server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) datalist = (( diff --git a/openstackclient/volume/client.py b/openstackclient/volume/client.py index d4800b8..0973868 100644 --- a/openstackclient/volume/client.py +++ b/openstackclient/volume/client.py @@ -19,7 +19,7 @@ from openstackclient.common import utils LOG = logging.getLogger(__name__) -DEFAULT_API_VERSION = '1' +DEFAULT_API_VERSION = '2' API_VERSION_OPTION = 'os_volume_api_version' API_NAME = "volume" API_VERSIONS = { diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py index 03c63a0..c668e36 100644 --- a/openstackclient/volume/v1/backup.py +++ b/openstackclient/volume/v1/backup.py @@ -57,8 +57,8 @@ class CreateBackup(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_id = utils.find_resource(volume_client.volumes, parsed_args.volume).id @@ -88,8 +88,8 @@ class DeleteBackup(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume for backup in parsed_args.backups: backup_id = utils.find_resource(volume_client.backups, @@ -113,8 +113,8 @@ class ListBackup(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) def _format_volume_id(volume_id): """Return a volume name if available @@ -172,8 +172,8 @@ class RestoreBackup(command.Command): help='Volume to restore to (name or ID)') return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume backup = utils.find_resource(volume_client.backups, parsed_args.backup) @@ -196,8 +196,8 @@ class ShowBackup(show.ShowOne): help='Backup to display (ID only)') return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume backup = utils.find_resource(volume_client.backups, parsed_args.backup) diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py index 8e909e3..d1c7011 100644 --- a/openstackclient/volume/v1/qos_specs.py +++ b/openstackclient/volume/v1/qos_specs.py @@ -45,8 +45,8 @@ class AssociateQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -88,8 +88,8 @@ class CreateQos(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume specs = {} specs.update({'consumer': parsed_args.consumer}) @@ -117,8 +117,8 @@ class DeleteQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', 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) @@ -153,8 +153,8 @@ class DisassociateQos(command.Command): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -174,8 +174,8 @@ class ListQos(lister.Lister): log = logging.getLogger(__name__ + '.ListQos') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_specs_list = volume_client.qos_specs.list() @@ -218,8 +218,8 @@ class SetQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -247,8 +247,8 @@ class ShowQos(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -287,8 +287,8 @@ class UnsetQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index e81efb5..de7bb5b 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -59,8 +59,8 @@ class CreateSnapshot(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_id = utils.find_resource(volume_client.volumes, parsed_args.volume).id @@ -93,8 +93,8 @@ class DeleteSnapshot(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume for snapshot in parsed_args.snapshots: snapshot_id = utils.find_resource(volume_client.volume_snapshots, @@ -118,8 +118,8 @@ class ListSnapshot(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) def _format_volume_id(volume_id): """Return a volume name if available @@ -194,8 +194,8 @@ class SetSnapshot(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, parsed_args.snapshot) @@ -231,8 +231,8 @@ class ShowSnapshot(show.ShowOne): help='Snapshot to display (name or ID)') return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, parsed_args.snapshot) @@ -267,8 +267,8 @@ class UnsetSnapshot(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume snapshot = utils.find_resource( volume_client.volume_snapshots, parsed_args.snapshot) diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index 884611e..52b0eb2 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -102,8 +102,8 @@ class CreateVolume(show.ShowOne): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image @@ -186,8 +186,8 @@ class DeleteVolume(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume for volume in parsed_args.volumes: volume_obj = utils.find_resource( @@ -230,8 +230,8 @@ class ListVolume(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume compute_client = self.app.client_manager.compute @@ -351,8 +351,8 @@ class SetVolume(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -399,8 +399,8 @@ class ShowVolume(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) # Map 'metadata' column to 'properties' @@ -441,8 +441,8 @@ class UnsetVolume(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume = utils.find_resource( volume_client.volumes, parsed_args.volume) diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py index d5c617b..d7765c7 100644 --- a/openstackclient/volume/v1/volume_type.py +++ b/openstackclient/volume/v1/volume_type.py @@ -47,8 +47,8 @@ class CreateVolumeType(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_type = volume_client.volume_types.create(parsed_args.name) volume_type._info.pop('extra_specs') @@ -75,8 +75,8 @@ class DeleteVolumeType(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_type_id = utils.find_resource( volume_client.volume_types, parsed_args.volume_type).id @@ -98,8 +98,8 @@ class ListVolumeType(lister.Lister): help='List additional fields in output') return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ('ID', 'Name', 'Extra Specs') column_headers = ('ID', 'Name', 'Properties') @@ -135,8 +135,8 @@ class SetVolumeType(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) @@ -170,8 +170,8 @@ class UnsetVolumeType(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index ac78ca1..b3a34ca 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -45,8 +45,8 @@ class AssociateQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -88,8 +88,8 @@ class CreateQos(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume specs = {} specs.update({'consumer': parsed_args.consumer}) @@ -117,8 +117,8 @@ class DeleteQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', 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) @@ -153,8 +153,8 @@ class DisassociateQos(command.Command): return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -174,8 +174,8 @@ class ListQos(lister.Lister): log = logging.getLogger(__name__ + '.ListQos') + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_specs_list = volume_client.qos_specs.list() @@ -218,8 +218,8 @@ class SetQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -247,8 +247,8 @@ class ShowQos(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) @@ -287,8 +287,8 @@ class UnsetQos(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, parsed_args.qos_spec) diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py index 4370cde..bbc92c4 100644 --- a/openstackclient/volume/v2/snapshot.py +++ b/openstackclient/volume/v2/snapshot.py @@ -186,8 +186,8 @@ class SetSnapshot(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, parsed_args.snapshot) @@ -256,8 +256,8 @@ class UnsetSnapshot(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume snapshot = utils.find_resource( volume_client.volume_snapshots, parsed_args.snapshot) diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index fe4a3ff..ad6215e 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -223,8 +223,8 @@ class ListVolume(lister.Lister): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume compute_client = self.app.client_manager.compute @@ -238,7 +238,7 @@ class ListVolume(lister.Lister): msg = '' for attachment in attachments: - server = attachment['id'] + server = attachment['server_id'] if server in server_cache: server = server_cache[server].name device = attachment['device'] @@ -335,8 +335,8 @@ class SetVolume(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -383,8 +383,8 @@ class ShowVolume(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -416,8 +416,8 @@ class UnsetVolume(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume = utils.find_resource( volume_client.volumes, parsed_args.volume) diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index fb0342c..8cca86f 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -66,8 +66,8 @@ class CreateVolumeType(show.ShowOne): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume @@ -127,8 +127,8 @@ class ListVolumeType(lister.Lister): help='List additional fields in output') return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) if parsed_args.long: columns = ['ID', 'Name', 'Description', 'Extra Specs'] column_headers = ['ID', 'Name', 'Description', 'Properties'] @@ -174,8 +174,8 @@ class SetVolumeType(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) @@ -250,8 +250,8 @@ class UnsetVolumeType(command.Command): ) return parser + @utils.log_method(log) def take_action(self, parsed_args): - self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, diff --git a/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po b/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po index 6c838a4..6758943 100644 --- a/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po +++ b/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po @@ -5,13 +5,15 @@ # # Translators: # Ettore Atalan <atalanttore@googlemail.com>, 2014-2015 +# Andreas Jaeger <jaegerandi@gmail.com>, 2015. #zanata +# OpenStack Infra <zanata@openstack.org>, 2015. #zanata msgid "" msgstr "" -"Project-Id-Version: python-openstackclient\n" +"Project-Id-Version: python-openstackclient 1.6.1.dev56\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-08-04 06:26+0000\n" -"PO-Revision-Date: 2015-06-14 18:41+0000\n" -"Last-Translator: openstackjenkins <jenkins@openstack.org>\n" +"POT-Creation-Date: 2015-09-21 06:09+0000\n" +"PO-Revision-Date: 2015-09-19 07:10+0000\n" +"Last-Translator: Andreas Jaeger <jaegerandi@gmail.com>\n" "Language-Team: German (http://www.transifex.com/openstack/python-" "openstackclient/language/de/)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" @@ -432,6 +434,9 @@ msgstr "Nach Bild suchen" msgid "Search by server status" msgstr "Nach Serverstatus suchen" +msgid "Search by user (admin only) (name or ID)" +msgstr "Nach Benutzer suchen (nur Administrator) (Name oder Kennung)" + msgid "Security group to add (name or ID)" msgstr "Zu hinzufügende Sicherheitsgruppe (Name oder Kennung)" @@ -472,6 +477,16 @@ msgstr "" "wiederholen)" msgid "" +"Set a scope, such as a project or domain, set a project scope with --os-" +"project-name, OS_PROJECT_NAME or auth.project_name, set a domain scope with " +"--os-domain-name, OS_DOMAIN_NAME or auth.domain_name" +msgstr "" +"Setzen Sie eine Eigenschaft, wie Projekt oder Domäne, setzen Sie eine " +"Projekteigenschaft mit --os-project-name, OS_PROJECT_NAME oder auth." +"project_name, setzen Sie eine Dömaneneigenschaft mit --os-domain-name, " +"OS_DOMAIN_NAME oder auth.domain_name." + +msgid "" "Set a service AUTH_URL, with --os-auth-url, OS_AUTH_URL or auth.auth_url\n" msgstr "" "Legen Sie eine Dienst-AUTH_URL mit --os-auth-url, OS_AUTH_URL oder auth." diff --git a/python-openstackclient/locale/python-openstackclient.pot b/python-openstackclient/locale/python-openstackclient.pot index e53b824..f613a5a 100644 --- a/python-openstackclient/locale/python-openstackclient.pot +++ b/python-openstackclient/locale/python-openstackclient.pot @@ -7,9 +7,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: python-openstackclient 1.5.1.dev136\n" +"Project-Id-Version: python-openstackclient 1.6.1.dev43\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-07-29 06:32+0000\n" +"POT-Creation-Date: 2015-09-11 06:10+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -48,7 +48,7 @@ msgid "Set a service URL, with --os-url, OS_URL or auth.url\n" msgstr "" #: openstackclient/compute/v2/availability_zone.py:72 -#: openstackclient/compute/v2/server.py:700 +#: openstackclient/compute/v2/server.py:718 #: openstackclient/identity/v2_0/endpoint.py:114 #: openstackclient/identity/v2_0/project.py:145 #: openstackclient/identity/v2_0/service.py:128 @@ -56,89 +56,89 @@ msgstr "" msgid "List additional fields in output" msgstr "" -#: openstackclient/compute/v2/server.py:154 -#: openstackclient/compute/v2/server.py:191 -#: openstackclient/compute/v2/server.py:542 -#: openstackclient/compute/v2/server.py:771 -#: openstackclient/compute/v2/server.py:805 -#: openstackclient/compute/v2/server.py:888 -#: openstackclient/compute/v2/server.py:912 -#: openstackclient/compute/v2/server.py:967 -#: openstackclient/compute/v2/server.py:1059 -#: openstackclient/compute/v2/server.py:1099 -#: openstackclient/compute/v2/server.py:1125 -#: openstackclient/compute/v2/server.py:1190 -#: openstackclient/compute/v2/server.py:1214 -#: openstackclient/compute/v2/server.py:1273 -#: openstackclient/compute/v2/server.py:1310 -#: openstackclient/compute/v2/server.py:1457 -#: openstackclient/compute/v2/server.py:1481 -#: openstackclient/compute/v2/server.py:1505 -#: openstackclient/compute/v2/server.py:1529 -#: openstackclient/compute/v2/server.py:1553 +#: openstackclient/compute/v2/server.py:161 +#: openstackclient/compute/v2/server.py:198 +#: openstackclient/compute/v2/server.py:549 +#: openstackclient/compute/v2/server.py:810 +#: openstackclient/compute/v2/server.py:844 +#: openstackclient/compute/v2/server.py:927 +#: openstackclient/compute/v2/server.py:951 +#: openstackclient/compute/v2/server.py:1006 +#: openstackclient/compute/v2/server.py:1098 +#: openstackclient/compute/v2/server.py:1138 +#: openstackclient/compute/v2/server.py:1164 +#: openstackclient/compute/v2/server.py:1229 +#: openstackclient/compute/v2/server.py:1253 +#: openstackclient/compute/v2/server.py:1312 +#: openstackclient/compute/v2/server.py:1349 +#: openstackclient/compute/v2/server.py:1496 +#: openstackclient/compute/v2/server.py:1520 +#: openstackclient/compute/v2/server.py:1544 +#: openstackclient/compute/v2/server.py:1568 +#: openstackclient/compute/v2/server.py:1592 msgid "Server (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:159 +#: openstackclient/compute/v2/server.py:166 msgid "Security group to add (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:196 +#: openstackclient/compute/v2/server.py:203 msgid "Volume to add (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:201 +#: openstackclient/compute/v2/server.py:208 msgid "Server internal device name for volume" msgstr "" -#: openstackclient/compute/v2/server.py:241 -#: openstackclient/compute/v2/server.py:1219 +#: openstackclient/compute/v2/server.py:248 +#: openstackclient/compute/v2/server.py:1258 msgid "New server name" msgstr "" -#: openstackclient/compute/v2/server.py:249 +#: openstackclient/compute/v2/server.py:256 msgid "Create server from this image" msgstr "" -#: openstackclient/compute/v2/server.py:254 +#: openstackclient/compute/v2/server.py:261 msgid "Create server from this volume" msgstr "" -#: openstackclient/compute/v2/server.py:260 +#: openstackclient/compute/v2/server.py:267 msgid "Create server with this flavor" msgstr "" -#: openstackclient/compute/v2/server.py:267 +#: openstackclient/compute/v2/server.py:274 msgid "Security group to assign to this server (repeat for multiple groups)" msgstr "" -#: openstackclient/compute/v2/server.py:273 +#: openstackclient/compute/v2/server.py:280 msgid "Keypair to inject into this server (optional extension)" msgstr "" -#: openstackclient/compute/v2/server.py:279 +#: openstackclient/compute/v2/server.py:286 msgid "Set a property on this server (repeat for multiple values)" msgstr "" -#: openstackclient/compute/v2/server.py:287 +#: openstackclient/compute/v2/server.py:294 msgid "File to inject into image before boot (repeat for multiple files)" msgstr "" -#: openstackclient/compute/v2/server.py:293 +#: openstackclient/compute/v2/server.py:300 msgid "User data file to serve from the metadata server" msgstr "" -#: openstackclient/compute/v2/server.py:298 +#: openstackclient/compute/v2/server.py:305 msgid "Select an availability zone for the server" msgstr "" -#: openstackclient/compute/v2/server.py:305 +#: openstackclient/compute/v2/server.py:312 msgid "" "Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> " "(optional extension)" msgstr "" -#: openstackclient/compute/v2/server.py:315 +#: openstackclient/compute/v2/server.py:322 msgid "" "Create a NIC on the server. Specify option multiple times to create " "multiple NICs. Either net-id or port-id must be provided, but not both. " @@ -147,314 +147,318 @@ msgid "" "-fixed-ip: IPv6 fixed address for NIC (optional)." msgstr "" -#: openstackclient/compute/v2/server.py:328 +#: openstackclient/compute/v2/server.py:335 msgid "Hints for the scheduler (optional extension)" msgstr "" -#: openstackclient/compute/v2/server.py:334 +#: openstackclient/compute/v2/server.py:341 msgid "" "Use specified volume as the config drive, or 'True' to use an ephemeral " "drive" msgstr "" -#: openstackclient/compute/v2/server.py:342 +#: openstackclient/compute/v2/server.py:349 msgid "Minimum number of servers to launch (default=1)" msgstr "" -#: openstackclient/compute/v2/server.py:349 +#: openstackclient/compute/v2/server.py:356 msgid "Maximum number of servers to launch (default=1)" msgstr "" -#: openstackclient/compute/v2/server.py:354 +#: openstackclient/compute/v2/server.py:361 msgid "Wait for build to complete" msgstr "" -#: openstackclient/compute/v2/server.py:394 +#: openstackclient/compute/v2/server.py:401 msgid "min instances should be <= max instances" msgstr "" -#: openstackclient/compute/v2/server.py:397 +#: openstackclient/compute/v2/server.py:404 msgid "min instances should be > 0" msgstr "" -#: openstackclient/compute/v2/server.py:400 +#: openstackclient/compute/v2/server.py:407 msgid "max instances should be > 0" msgstr "" -#: openstackclient/compute/v2/server.py:436 +#: openstackclient/compute/v2/server.py:443 msgid "either net-id or port-id should be specified but not both" msgstr "" -#: openstackclient/compute/v2/server.py:458 +#: openstackclient/compute/v2/server.py:465 msgid "can't create server with port specified since neutron not enabled" msgstr "" -#: openstackclient/compute/v2/server.py:523 +#: openstackclient/compute/v2/server.py:530 #, python-format msgid "Error creating server: %s" msgstr "" -#: openstackclient/compute/v2/server.py:525 +#: openstackclient/compute/v2/server.py:532 msgid "" "\n" "Error creating server" msgstr "" -#: openstackclient/compute/v2/server.py:547 +#: openstackclient/compute/v2/server.py:554 msgid "Name of new image (default is server name)" msgstr "" -#: openstackclient/compute/v2/server.py:552 +#: openstackclient/compute/v2/server.py:559 msgid "Wait for image create to complete" msgstr "" -#: openstackclient/compute/v2/server.py:582 +#: openstackclient/compute/v2/server.py:589 #, python-format msgid "Error creating server snapshot: %s" msgstr "" -#: openstackclient/compute/v2/server.py:584 +#: openstackclient/compute/v2/server.py:591 msgid "" "\n" "Error creating server snapshot" msgstr "" -#: openstackclient/compute/v2/server.py:606 +#: openstackclient/compute/v2/server.py:613 msgid "Server(s) to delete (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:611 +#: openstackclient/compute/v2/server.py:618 msgid "Wait for delete to complete" msgstr "" -#: openstackclient/compute/v2/server.py:630 +#: openstackclient/compute/v2/server.py:637 #, python-format msgid "Error deleting server: %s" msgstr "" -#: openstackclient/compute/v2/server.py:632 +#: openstackclient/compute/v2/server.py:639 msgid "" "\n" "Error deleting server" msgstr "" -#: openstackclient/compute/v2/server.py:647 +#: openstackclient/compute/v2/server.py:654 msgid "Only return instances that match the reservation" msgstr "" -#: openstackclient/compute/v2/server.py:652 +#: openstackclient/compute/v2/server.py:659 msgid "Regular expression to match IP addresses" msgstr "" -#: openstackclient/compute/v2/server.py:657 +#: openstackclient/compute/v2/server.py:664 msgid "Regular expression to match IPv6 addresses" msgstr "" -#: openstackclient/compute/v2/server.py:662 +#: openstackclient/compute/v2/server.py:669 msgid "Regular expression to match names" msgstr "" -#: openstackclient/compute/v2/server.py:667 +#: openstackclient/compute/v2/server.py:674 msgid "Regular expression to match instance name (admin only)" msgstr "" -#: openstackclient/compute/v2/server.py:673 +#: openstackclient/compute/v2/server.py:680 msgid "Search by server status" msgstr "" -#: openstackclient/compute/v2/server.py:678 +#: openstackclient/compute/v2/server.py:685 msgid "Search by flavor" msgstr "" -#: openstackclient/compute/v2/server.py:683 +#: openstackclient/compute/v2/server.py:690 msgid "Search by image" msgstr "" -#: openstackclient/compute/v2/server.py:688 +#: openstackclient/compute/v2/server.py:695 msgid "Search by hostname" msgstr "" -#: openstackclient/compute/v2/server.py:694 +#: openstackclient/compute/v2/server.py:701 msgid "Include all projects (admin only)" msgstr "" -#: openstackclient/compute/v2/server.py:810 +#: openstackclient/compute/v2/server.py:711 +msgid "Search by user (admin only) (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:849 msgid "Target hostname" msgstr "" -#: openstackclient/compute/v2/server.py:818 +#: openstackclient/compute/v2/server.py:857 msgid "Perform a shared live migration (default)" msgstr "" -#: openstackclient/compute/v2/server.py:824 +#: openstackclient/compute/v2/server.py:863 msgid "Perform a block live migration" msgstr "" -#: openstackclient/compute/v2/server.py:831 +#: openstackclient/compute/v2/server.py:870 msgid "Allow disk over-commit on the destination host" msgstr "" -#: openstackclient/compute/v2/server.py:838 +#: openstackclient/compute/v2/server.py:877 msgid "Do not over-commit disk on the destination host (default)" msgstr "" -#: openstackclient/compute/v2/server.py:844 -#: openstackclient/compute/v2/server.py:1145 +#: openstackclient/compute/v2/server.py:883 +#: openstackclient/compute/v2/server.py:1184 msgid "Wait for resize to complete" msgstr "" -#: openstackclient/compute/v2/server.py:872 -#: openstackclient/compute/v2/server.py:1170 +#: openstackclient/compute/v2/server.py:911 +#: openstackclient/compute/v2/server.py:1209 msgid "Complete\n" msgstr "" -#: openstackclient/compute/v2/server.py:874 +#: openstackclient/compute/v2/server.py:913 msgid "" "\n" "Error migrating server" msgstr "" -#: openstackclient/compute/v2/server.py:921 +#: openstackclient/compute/v2/server.py:960 msgid "Perform a hard reboot" msgstr "" -#: openstackclient/compute/v2/server.py:929 +#: openstackclient/compute/v2/server.py:968 msgid "Perform a soft reboot" msgstr "" -#: openstackclient/compute/v2/server.py:934 +#: openstackclient/compute/v2/server.py:973 msgid "Wait for reboot to complete" msgstr "" -#: openstackclient/compute/v2/server.py:951 +#: openstackclient/compute/v2/server.py:990 msgid "" "\n" "Reboot complete\n" msgstr "" -#: openstackclient/compute/v2/server.py:953 +#: openstackclient/compute/v2/server.py:992 msgid "" "\n" "Error rebooting server\n" msgstr "" -#: openstackclient/compute/v2/server.py:973 +#: openstackclient/compute/v2/server.py:1012 msgid "Recreate server from this image" msgstr "" -#: openstackclient/compute/v2/server.py:983 +#: openstackclient/compute/v2/server.py:1022 msgid "Wait for rebuild to complete" msgstr "" -#: openstackclient/compute/v2/server.py:1004 +#: openstackclient/compute/v2/server.py:1043 msgid "" "\n" "Complete\n" msgstr "" -#: openstackclient/compute/v2/server.py:1006 +#: openstackclient/compute/v2/server.py:1045 msgid "" "\n" "Error rebuilding server" msgstr "" -#: openstackclient/compute/v2/server.py:1023 +#: openstackclient/compute/v2/server.py:1062 msgid "Name or ID of server to use" msgstr "" -#: openstackclient/compute/v2/server.py:1028 +#: openstackclient/compute/v2/server.py:1067 msgid "Name or ID of security group to remove from server" msgstr "" -#: openstackclient/compute/v2/server.py:1064 +#: openstackclient/compute/v2/server.py:1103 msgid "Volume to remove (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:1130 +#: openstackclient/compute/v2/server.py:1169 msgid "Resize server to specified flavor" msgstr "" -#: openstackclient/compute/v2/server.py:1135 +#: openstackclient/compute/v2/server.py:1174 msgid "Confirm server resize is complete" msgstr "" -#: openstackclient/compute/v2/server.py:1140 +#: openstackclient/compute/v2/server.py:1179 msgid "Restore server state before resize" msgstr "" -#: openstackclient/compute/v2/server.py:1172 +#: openstackclient/compute/v2/server.py:1211 msgid "" "\n" "Error resizing server" msgstr "" -#: openstackclient/compute/v2/server.py:1224 +#: openstackclient/compute/v2/server.py:1263 msgid "Set new root password (interactive only)" msgstr "" -#: openstackclient/compute/v2/server.py:1230 +#: openstackclient/compute/v2/server.py:1269 msgid "" "Property to add/change for this server (repeat option to set multiple " "properties)" msgstr "" -#: openstackclient/compute/v2/server.py:1254 +#: openstackclient/compute/v2/server.py:1293 msgid "New password: " msgstr "" -#: openstackclient/compute/v2/server.py:1255 +#: openstackclient/compute/v2/server.py:1294 msgid "Retype new password: " msgstr "" -#: openstackclient/compute/v2/server.py:1259 +#: openstackclient/compute/v2/server.py:1298 msgid "Passwords do not match, password unchanged" msgstr "" -#: openstackclient/compute/v2/server.py:1279 +#: openstackclient/compute/v2/server.py:1318 msgid "Display server diagnostics information" msgstr "" -#: openstackclient/compute/v2/server.py:1292 +#: openstackclient/compute/v2/server.py:1331 msgid "Error retrieving diagnostics data" msgstr "" -#: openstackclient/compute/v2/server.py:1315 +#: openstackclient/compute/v2/server.py:1354 msgid "Login name (ssh -l option)" msgstr "" -#: openstackclient/compute/v2/server.py:1327 +#: openstackclient/compute/v2/server.py:1366 msgid "Destination port (ssh -p option)" msgstr "" -#: openstackclient/compute/v2/server.py:1339 +#: openstackclient/compute/v2/server.py:1378 msgid "Private key file (ssh -i option)" msgstr "" -#: openstackclient/compute/v2/server.py:1350 +#: openstackclient/compute/v2/server.py:1389 msgid "Options in ssh_config(5) format (ssh -o option)" msgstr "" -#: openstackclient/compute/v2/server.py:1364 +#: openstackclient/compute/v2/server.py:1403 msgid "Use only IPv4 addresses" msgstr "" -#: openstackclient/compute/v2/server.py:1371 +#: openstackclient/compute/v2/server.py:1410 msgid "Use only IPv6 addresses" msgstr "" -#: openstackclient/compute/v2/server.py:1380 +#: openstackclient/compute/v2/server.py:1419 msgid "Use public IP address" msgstr "" -#: openstackclient/compute/v2/server.py:1388 +#: openstackclient/compute/v2/server.py:1427 msgid "Use private IP address" msgstr "" -#: openstackclient/compute/v2/server.py:1395 +#: openstackclient/compute/v2/server.py:1434 msgid "Use other IP address (public, private, etc)" msgstr "" -#: openstackclient/compute/v2/server.py:1560 +#: openstackclient/compute/v2/server.py:1599 msgid "Property key to remove from server (repeat to unset multiple values)" msgstr "" @@ -669,7 +673,7 @@ msgstr "" msgid "No service catalog with a type, name or ID of '%s' exists." msgstr "" -#: openstackclient/identity/v2_0/token.py:54 +#: openstackclient/identity/v2_0/token.py:55 msgid "Token to be deleted" msgstr "" diff --git a/requirements.txt b/requirements.txt index b575125..c638ed1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,20 +1,20 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr<2.0,>=1.4 +pbr>=1.6 six>=1.9.0 Babel>=1.3 cliff>=1.14.0 # Apache-2.0 cliff-tablib>=1.0 -os-client-config>=1.4.0 -oslo.config>=1.11.0 # Apache-2.0 +os-client-config!=1.6.2,>=1.4.0 +oslo.config>=2.3.0 # Apache-2.0 oslo.i18n>=1.5.0 # Apache-2.0 -oslo.utils>=1.9.0 # Apache-2.0 +oslo.utils>=2.0.0 # Apache-2.0 python-glanceclient>=0.18.0 python-keystoneclient>=1.6.0 -python-novaclient>=2.26.0 +python-novaclient>=2.28.1 python-cinderclient>=1.3.1 -python-neutronclient<3,>=2.6.0 +python-neutronclient>=2.6.0 requests>=2.5.2 stevedore>=1.5.0 # Apache-2.0 @@ -316,6 +316,7 @@ openstack.image.v1 = openstack.image.v2 = image_add_project = openstackclient.image.v2.image:AddProjectToImage + image_create = openstackclient.image.v2.image:CreateImage image_delete = openstackclient.image.v2.image:DeleteImage image_list = openstackclient.image.v2.image:ListImage image_remove_project = openstackclient.image.v2.image:RemoveProjectImage @@ -25,5 +25,5 @@ except ImportError: pass setuptools.setup( - setup_requires=['pbr>=1.3'], + setup_requires=['pbr>=1.8'], pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt index 23edc37..25d0628 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -15,4 +15,4 @@ os-testr>=0.1.0 testrepository>=0.0.18 testtools>=1.4.0 WebOb>=1.2.3 -tempest-lib>=0.6.1 +tempest-lib>=0.8.0 |
