Hello community,

here is the log from the commit of package python-cinderclient for 
openSUSE:Factory checked in at 2018-02-14 10:50:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cinderclient (Old)
 and      /work/SRC/openSUSE:Factory/.python-cinderclient.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cinderclient"

Wed Feb 14 10:50:23 2018 rev:31 rq:575931 version:3.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cinderclient/python-cinderclient.changes  
2018-01-24 15:30:49.229475138 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-cinderclient.new/python-cinderclient.changes 
    2018-02-14 10:50:24.184315911 +0100
@@ -1,0 +2,16 @@
+Mon Feb 12 09:52:55 UTC 2018 - cloud-de...@suse.de
+
+- update to version 3.5.0 (bsc#1078607)
+  - Updated from global requirements
+  - Bump API microversion to 3.50
+  - Add api_version wraps for generic volume groups
+  - Add service cleanup command
+  - Fix 'cluster' paramter using for v3 volume manage
+  - Migrate to keystoneauth identity cli opts.
+  - Removes unicode 'u' response for "cinder get-capabilities"
+  - Add snapshot_id param note for backup-create
+  - Support for reporting backend state in service list
+  - Fix v2 volume unit tests
+  - Add cluster support in manage listings
+
+-------------------------------------------------------------------

Old:
----
  python-cinderclient-3.4.0.tar.gz

New:
----
  python-cinderclient-3.5.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-cinderclient.spec ++++++
--- /var/tmp/diff_new_pack.nt9vid/_old  2018-02-14 10:50:24.812293312 +0100
+++ /var/tmp/diff_new_pack.nt9vid/_new  2018-02-14 10:50:24.812293312 +0100
@@ -17,23 +17,23 @@
 
 
 Name:           python-cinderclient
-Version:        3.4.0
+Version:        3.5.0
 Release:        0
 Summary:        Python API and CLI for OpenStack Cinder
 License:        Apache-2.0
 Group:          Development/Languages/Python
 Url:            https://launchpad.net/python-cinderclient
-Source0:        
https://files.pythonhosted.org/packages/source/p/python-cinderclient/python-cinderclient-3.4.0.tar.gz
+Source0:        
https://files.pythonhosted.org/packages/source/p/python-cinderclient/python-cinderclient-3.5.0.tar.gz
 BuildRequires:  openstack-macros
 BuildRequires:  python-devel
 BuildRequires:  python2-PrettyTable >= 0.7.1
 BuildRequires:  python2-ddt >= 1.0.1
 BuildRequires:  python2-fixtures >= 3.0.0
-BuildRequires:  python2-keystoneauth1 >= 3.2.0
+BuildRequires:  python2-keystoneauth1 >= 3.3.0
 BuildRequires:  python2-mock >= 2.0.0
 BuildRequires:  python2-os-testr >= 1.0.0
 BuildRequires:  python2-oslo.serialization >= 2.18.0
-BuildRequires:  python2-oslo.utils >= 3.31.0
+BuildRequires:  python2-oslo.utils >= 3.33.0
 BuildRequires:  python2-pbr >= 2.0.0
 BuildRequires:  python2-python-subunit >= 1.0.0
 BuildRequires:  python2-requests >= 2.14.2
@@ -45,11 +45,11 @@
 BuildRequires:  python3-ddt >= 1.0.1
 BuildRequires:  python3-devel
 BuildRequires:  python3-fixtures >= 3.0.0
-BuildRequires:  python3-keystoneauth1 >= 3.2.0
+BuildRequires:  python3-keystoneauth1 >= 3.3.0
 BuildRequires:  python3-mock >= 2.0.0
 BuildRequires:  python3-os-testr >= 1.0.0
 BuildRequires:  python3-oslo.serialization >= 2.18.0
-BuildRequires:  python3-oslo.utils >= 3.31.0
+BuildRequires:  python3-oslo.utils >= 3.33.0
 BuildRequires:  python3-pbr >= 2.0.0
 BuildRequires:  python3-python-subunit >= 1.0.0
 BuildRequires:  python3-requests >= 2.14.2
@@ -59,9 +59,9 @@
 BuildRequires:  python3-testtools >= 2.2.0
 Requires:       python-Babel >= 2.3.4
 Requires:       python-PrettyTable >= 0.7.1
-Requires:       python-keystoneauth1 >= 3.2.0
+Requires:       python-keystoneauth1 >= 3.3.0
 Requires:       python-oslo.i18n >= 3.15.3
-Requires:       python-oslo.utils >= 3.31.0
+Requires:       python-oslo.utils >= 3.33.0
 Requires:       python-requests >= 2.14.2
 Requires:       python-simplejson >= 3.5.1
 Requires:       python-six >= 1.10.0
@@ -95,7 +95,7 @@
 This package contains auto-generated documentation.
 
 %prep
-%autosetup -p1 -n python-cinderclient-3.4.0
+%autosetup -p1 -n python-cinderclient-3.5.0
 %py_req_cleanup
 sed -i 's/^warning-is-error.*/warning-is-error = 0/g' setup.cfg
 

++++++ python-cinderclient-3.4.0.tar.gz -> python-cinderclient-3.5.0.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/AUTHORS 
new/python-cinderclient-3.5.0/AUTHORS
--- old/python-cinderclient-3.4.0/AUTHORS       2018-01-08 15:02:53.000000000 
+0100
+++ new/python-cinderclient-3.5.0/AUTHORS       2018-01-24 23:18:18.000000000 
+0100
@@ -1,6 +1,7 @@
 Aaron Rosen <aaronoro...@gmail.com>
 Abhijeet Malawade <abhijeet.malaw...@gmail.com>
 Abhishek Kekane <abhishek.kek...@nttdata.com>
+Abijitha Nadagouda <abijitha.nadago...@tatacommunications.com>
 Adam Gandelman <adam.gandel...@canonical.com>
 Adrien Vergé <adrienve...@gmail.com>
 Akira KAMIO <aka...@yahoo-corp.jp>
@@ -89,6 +90,7 @@
 Jay Lau <liu...@cn.ibm.com>
 Jay S Bryant <jsbry...@us.ibm.com>
 Jay S. Bryant <jsbry...@us.ibm.com>
+Jay S. Bryant <jungleb...@electronicjungle.net>
 Jeremy Liu <liuji...@gohighsec.com>
 Jeremy Stanley <fu...@yuggoth.org>
 Joe Gordon <joe.gord...@gmail.com>
@@ -206,6 +208,7 @@
 Yaguang Tang <yagu...@umcloud.com>
 Yuriy Nesenenko <ynesene...@mirantis.com>
 Yusuke Hayashi <hayashi-yus...@jp.fujitsu.com>
+Zhao Chao <zhaochao1...@gmail.com>
 Zhengguang <zhengguan...@gmail.com>
 Zhenguo Niu <niu.zgli...@gmail.com>
 Zhenguo Niu <niuzhen...@huawei.com>
@@ -288,5 +291,6 @@
 zhangdaolong <zhangdaol...@fiberhome.com>
 zhangyanxian <zhangyanxianm...@163.com>
 zheng yin <yin.zh...@easystack.cn>
+zhengyin <zheng...@chinac.com>
 zhu.rong <zhu.r...@99cloud.net>
 zwei <leid...@unitedstack.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/ChangeLog 
new/python-cinderclient-3.5.0/ChangeLog
--- old/python-cinderclient-3.4.0/ChangeLog     2018-01-08 15:02:52.000000000 
+0100
+++ new/python-cinderclient-3.5.0/ChangeLog     2018-01-24 23:18:18.000000000 
+0100
@@ -1,6 +1,19 @@
 CHANGES
 =======
 
+3.5.0
+-----
+
+* Bump API microversion to 3.50
+* Removes unicode 'u' response for "cinder get-capabilities"
+* Updated from global requirements
+* Migrate to keystoneauth identity cli opts
+* Add api\_version wraps for generic volume groups
+* Add snapshot\_id param note for backup-create
+* Support for reporting backend state in service list
+* Fix v2 volume unit tests
+* Fix 'cluster' paramter using for v3 volume manage
+
 3.4.0
 -----
 
@@ -30,6 +43,8 @@
 * Updated from global requirements
 * Revert "Bump MAX version of client to 3.45"
 * Use generic user for both zuul v2 and v3
+* Add service cleanup command
+* Add cluster support in manage listings
 * Add cluster support in migration and manage
 * Add .stestr.conf configuration
 * Let keystoneauth set the microversion header
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/PKG-INFO 
new/python-cinderclient-3.5.0/PKG-INFO
--- old/python-cinderclient-3.4.0/PKG-INFO      2018-01-08 15:02:54.000000000 
+0100
+++ new/python-cinderclient-3.5.0/PKG-INFO      2018-01-24 23:18:19.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-cinderclient
-Version: 3.4.0
+Version: 3.5.0
 Summary: OpenStack Block Storage API Client Library
 Home-page: https://docs.openstack.org/python-cinderclient/latest/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/api_versions.py 
new/python-cinderclient-3.5.0/cinderclient/api_versions.py
--- old/python-cinderclient-3.4.0/cinderclient/api_versions.py  2018-01-08 
15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/api_versions.py  2018-01-24 
23:14:35.000000000 +0100
@@ -29,7 +29,7 @@
 # key is a deprecated version and value is an alternative version.
 DEPRECATED_VERSIONS = {"1": "2"}
 DEPRECATED_VERSION = "2.0"
-MAX_VERSION = "3.48"
+MAX_VERSION = "3.50"
 MIN_VERSION = "3.0"
 
 _SUBSTITUTIONS = {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/shell.py 
new/python-cinderclient-3.5.0/cinderclient/shell.py
--- old/python-cinderclient-3.4.0/cinderclient/shell.py 2018-01-08 
15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/shell.py 2018-01-24 
23:14:35.000000000 +0100
@@ -138,23 +138,6 @@
                                               default=False),
                             help=_('Shows debugging output.'))
 
-        parser.add_argument('--os-auth-system',
-                            metavar='<os-auth-system>',
-                            dest='os_auth_type',
-                            default=(utils.env('OS_AUTH_TYPE') or
-                                     utils.env('OS_AUTH_SYSTEM')),
-                            help=_('DEPRECATED! Use --os-auth-type. '
-                                   'Defaults to env[OS_AUTH_SYSTEM].'))
-        parser.add_argument('--os_auth_system',
-                            help=argparse.SUPPRESS)
-        parser.add_argument('--os-auth-type',
-                            metavar='<os-auth-type>',
-                            dest='os_auth_type',
-                            default=(utils.env('OS_AUTH_TYPE') or
-                                     utils.env('OS_AUTH_SYSTEM')),
-                            help=_('Defaults to env[OS_AUTH_TYPE].'))
-        parser.add_argument('--os_auth_type',
-                            help=argparse.SUPPRESS)
         parser.add_argument('--service-type',
                             metavar='<service-type>',
                             help=_('Service type. '
@@ -255,11 +238,16 @@
         return parser
 
     def _append_global_identity_args(self, parser):
-        # FIXME(bklei): these are global identity (Keystone) arguments which
-        # should be consistent and shared by all service clients. Therefore,
-        # they should be provided by python-keystoneclient. We will need to
-        # refactor this code once this functionality is available in
-        # python-keystoneclient.
+        loading.register_session_argparse_arguments(parser)
+
+        # Use "password" auth plugin as default and keep the explicit
+        # "--os-token" arguments below for backward compatibility.
+        default_auth_plugin = 'password'
+
+        # Passing [] to loading.register_auth_argparse_arguments to avoid
+        # the auth_type being overriden by the command line.
+        loading.register_auth_argparse_arguments(
+            parser, [], default=default_auth_plugin)
 
         parser.add_argument(
             '--os-auth-strategy', metavar='<auth-strategy>',
@@ -271,128 +259,88 @@
             '--os_auth_strategy',
             help=argparse.SUPPRESS)
 
-        parser.add_argument('--os-username',
-                            metavar='<auth-user-name>',
-                            default=utils.env('OS_USERNAME',
-                                              'CINDER_USERNAME'),
-                            help=_('OpenStack user name. '
-                            'Default=env[OS_USERNAME].'))
+        # Change os_auth_type default value defined by
+        # register_auth_argparse_arguments to be backward compatible
+        # with OS_AUTH_SYSTEM.
+        env_plugin = utils.env('OS_AUTH_TYPE',
+                               'OS_AUTH_PLUGIN',
+                               'OS_AUTH_SYSTEM')
+        parser.set_defaults(os_auth_type=env_plugin)
+        parser.add_argument('--os_auth_type',
+                            help=argparse.SUPPRESS)
+
+        parser.add_argument('--os-auth-system',
+                            metavar='<os-auth-system>',
+                            dest='os_auth_type',
+                            default=env_plugin,
+                            help=_('DEPRECATED! Use --os-auth-type. '
+                                   'Defaults to env[OS_AUTH_SYSTEM].'))
+        parser.add_argument('--os_auth_system',
+                            help=argparse.SUPPRESS)
+
+        parser.set_defaults(os_username=utils.env('OS_USERNAME',
+                                                  'CINDER_USERNAME'))
         parser.add_argument('--os_username',
                             help=argparse.SUPPRESS)
 
-        parser.add_argument('--os-password',
-                            metavar='<auth-password>',
-                            default=utils.env('OS_PASSWORD',
-                                              'CINDER_PASSWORD'),
-                            help=_('Password for OpenStack user. '
-                            'Default=env[OS_PASSWORD].'))
+        parser.set_defaults(os_password=utils.env('OS_PASSWORD',
+                                                  'CINDER_PASSWORD'))
         parser.add_argument('--os_password',
                             help=argparse.SUPPRESS)
 
-        parser.add_argument('--os-tenant-name',
-                            metavar='<auth-tenant-name>',
-                            default=utils.env('OS_TENANT_NAME',
-                                              'OS_PROJECT_NAME',
-                                              'CINDER_PROJECT_ID'),
-                            help=_('Tenant name. '
-                            'Default=env[OS_TENANT_NAME].'))
+        # tenant_name is deprecated by project_name in keystoneauth
+        parser.set_defaults(os_project_name=utils.env('OS_PROJECT_NAME',
+                                                      'OS_TENANT_NAME',
+                                                      'CINDER_PROJECT_ID'))
         parser.add_argument('--os_tenant_name',
+                            dest='os_project_name',
                             help=argparse.SUPPRESS)
+        parser.add_argument(
+            '--os_project_name',
+            help=argparse.SUPPRESS)
 
-        parser.add_argument('--os-tenant-id',
-                            metavar='<auth-tenant-id>',
-                            default=utils.env('OS_TENANT_ID',
-                                              'OS_PROJECT_ID',
-                                              'CINDER_TENANT_ID'),
-                            help=_('ID for the tenant. '
-                            'Default=env[OS_TENANT_ID].'))
+        # tenant_id is deprecated by project_id in keystoneauth
+        parser.set_defaults(os_project_id=utils.env('OS_PROJECT_ID',
+                                                    'OS_TENANT_ID',
+                                                    'CINDER_TENANT_ID'))
         parser.add_argument('--os_tenant_id',
+                            dest='os_project_id',
                             help=argparse.SUPPRESS)
+        parser.add_argument(
+            '--os_project_id',
+            help=argparse.SUPPRESS)
 
-        parser.add_argument('--os-auth-url',
-                            metavar='<auth-url>',
-                            default=utils.env('OS_AUTH_URL',
-                                              'CINDER_URL'),
-                            help=_('URL for the authentication service. '
-                            'Default=env[OS_AUTH_URL].'))
+        parser.set_defaults(os_auth_url=utils.env('OS_AUTH_URL',
+                                                  'CINDER_URL'))
         parser.add_argument('--os_auth_url',
                             help=argparse.SUPPRESS)
 
-        parser.add_argument(
-            '--os-user-id', metavar='<auth-user-id>',
-            default=utils.env('OS_USER_ID'),
-            help=_('Authentication user ID (Env: OS_USER_ID).'))
-
+        parser.set_defaults(os_user_id=utils.env('OS_USER_ID'))
         parser.add_argument(
             '--os_user_id',
             help=argparse.SUPPRESS)
 
-        parser.add_argument(
-            '--os-user-domain-id',
-            metavar='<auth-user-domain-id>',
-            default=utils.env('OS_USER_DOMAIN_ID'),
-            help=_('OpenStack user domain ID. '
-            'Defaults to env[OS_USER_DOMAIN_ID].'))
-
+        parser.set_defaults(
+            os_user_domain_id=utils.env('OS_USER_DOMAIN_ID'))
         parser.add_argument(
             '--os_user_domain_id',
             help=argparse.SUPPRESS)
 
-        parser.add_argument(
-            '--os-user-domain-name',
-            metavar='<auth-user-domain-name>',
-            default=utils.env('OS_USER_DOMAIN_NAME'),
-            help=_('OpenStack user domain name. '
-                 'Defaults to env[OS_USER_DOMAIN_NAME].'))
-
+        parser.set_defaults(
+            os_user_domain_name=utils.env('OS_USER_DOMAIN_NAME'))
         parser.add_argument(
             '--os_user_domain_name',
             help=argparse.SUPPRESS)
 
-        parser.add_argument(
-            '--os-project-id',
-            metavar='<auth-project-id>',
-            default=utils.env('OS_PROJECT_ID'),
-            help=_('Another way to specify tenant ID. '
-            'This option is mutually exclusive with '
-            ' --os-tenant-id. '
-            'Defaults to env[OS_PROJECT_ID].'))
+        parser.set_defaults(
+            os_project_domain_id=utils.env('OS_PROJECT_DOMAIN_ID'))
 
-        parser.add_argument(
-            '--os_project_id',
-            help=argparse.SUPPRESS)
+        parser.set_defaults(
+            os_project_domain_name=utils.env('OS_PROJECT_DOMAIN_NAME'))
 
-        parser.add_argument(
-            '--os-project-name',
-            metavar='<auth-project-name>',
-            default=utils.env('OS_PROJECT_NAME'),
-            help=_('Another way to specify tenant name. '
-                 'This option is mutually exclusive with '
-                 ' --os-tenant-name. '
-                 'Defaults to env[OS_PROJECT_NAME].'))
-
-        parser.add_argument(
-            '--os_project_name',
-            help=argparse.SUPPRESS)
-
-        parser.add_argument(
-            '--os-project-domain-id',
-            metavar='<auth-project-domain-id>',
-            default=utils.env('OS_PROJECT_DOMAIN_ID'),
-            help=_('Defaults to env[OS_PROJECT_DOMAIN_ID].'))
-
-        parser.add_argument(
-            '--os-project-domain-name',
-            metavar='<auth-project-domain-name>',
-            default=utils.env('OS_PROJECT_DOMAIN_NAME'),
-            help=_('Defaults to env[OS_PROJECT_DOMAIN_NAME].'))
-
-        parser.add_argument('--os-region-name',
-                            metavar='<region-name>',
-                            default=utils.env('OS_REGION_NAME',
-                                              'CINDER_REGION_NAME'),
-                            help=_('Region name. '
-                            'Default=env[OS_REGION_NAME].'))
+        parser.set_defaults(
+            os_region_name=utils.env('OS_REGION_NAME',
+                                     'CINDER_REGION_NAME'))
         parser.add_argument('--os_region_name',
                             help=argparse.SUPPRESS)
 
@@ -412,8 +360,6 @@
             '--os_url',
             help=argparse.SUPPRESS)
 
-        # Register the CLI arguments that have moved to the session object.
-        loading.register_session_argparse_arguments(parser)
         parser.set_defaults(insecure=utils.env('CINDERCLIENT_INSECURE',
                                                default=False))
 
@@ -646,13 +592,13 @@
             self.do_bash_completion(args)
             return 0
 
-        (os_username, os_password, os_tenant_name, os_auth_url,
-         os_region_name, os_tenant_id, endpoint_type,
+        (os_username, os_password, os_project_name, os_auth_url,
+         os_region_name, os_project_id, endpoint_type,
          service_type, service_name, volume_service_name, os_endpoint,
          cacert, os_auth_type) = (
              args.os_username, args.os_password,
-             args.os_tenant_name, args.os_auth_url,
-             args.os_region_name, args.os_tenant_id,
+             args.os_project_name, args.os_auth_url,
+             args.os_region_name, args.os_project_id,
              args.os_endpoint_type,
              args.service_type, args.service_name,
              args.volume_service_name,
@@ -675,12 +621,11 @@
         # for os_username or os_password but for compatibility it is not.
 
         # V3 stuff
-        project_info_provided = ((self.options.os_tenant_name or
-                                  self.options.os_tenant_id) or
-                                 (self.options.os_project_name and
+        project_info_provided = ((self.options.os_project_name and
                                   (self.options.os_project_domain_name or
                                    self.options.os_project_domain_id)) or
-                                 self.options.os_project_id)
+                                 self.options.os_project_id or
+                                 self.options.os_project_name)
 
         # NOTE(e0ne): if auth_session exists it means auth plugin created
         # session and we don't need to check for password and other
@@ -752,9 +697,9 @@
 
         self.cs = client.Client(
             api_version, os_username,
-            os_password, os_tenant_name, os_auth_url,
+            os_password, os_project_name, os_auth_url,
             region_name=os_region_name,
-            tenant_id=os_tenant_id,
+            tenant_id=os_project_id,
             endpoint_type=endpoint_type,
             extensions=self.extensions,
             service_type=service_type,
@@ -852,9 +797,8 @@
 
         username = self.options.os_username
         password = self.options.os_password
-        tenant_id = self.options.os_tenant_id or self.options.os_project_id
-        tenant_name = (self.options.os_tenant_name or
-                       self.options.os_project_name)
+        tenant_id = self.options.os_project_id
+        tenant_name = self.options.os_project_name
 
         return v2_auth.Password(
             v2_auth_url,
@@ -870,9 +814,8 @@
         user_domain_name = self.options.os_user_domain_name
         user_domain_id = self.options.os_user_domain_id
         password = self.options.os_password
-        project_id = self.options.os_project_id or self.options.os_tenant_id
-        project_name = (self.options.os_project_name or
-                        self.options.os_tenant_name)
+        project_id = self.options.os_project_id
+        project_name = self.options.os_project_name
         project_domain_name = self.options.os_project_domain_name
         project_domain_id = self.options.os_project_domain_id
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/test_shell.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/test_shell.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/test_shell.py 
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/test_shell.py 
2018-01-24 23:14:35.000000000 +0100
@@ -19,6 +19,7 @@
 import fixtures
 import keystoneauth1.exceptions as ks_exc
 from keystoneauth1.exceptions import DiscoveryFailure
+from keystoneauth1.identity.generic.password import Password as ks_password
 from keystoneauth1 import session
 import mock
 import requests_mock
@@ -92,6 +93,21 @@
         args, __ = _shell.get_base_parser().parse_known_args([])
         self.assertEqual('noauth', args.os_auth_type)
 
+    @mock.patch.object(cinderclient.shell.OpenStackCinderShell,
+                       '_get_keystone_session')
+    @mock.patch.object(cinderclient.client.SessionClient, 'authenticate',
+                       side_effect=RuntimeError())
+    def test_password_auth_type(self, mock_authenticate,
+                                mock_get_session):
+        self.make_env(include={'OS_AUTH_TYPE': 'password'})
+        _shell = shell.OpenStackCinderShell()
+
+        # We crash the command after Client instantiation because this test
+        # focuses only keystoneauth1 indentity cli opts parsing.
+        self.assertRaises(RuntimeError, _shell.main, ['list'])
+        self.assertIsInstance(_shell.cs.client.session.auth,
+                              ks_password)
+
     def test_help_unknown_command(self):
         self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/v2/fakes.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/v2/fakes.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/v2/fakes.py   
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/v2/fakes.py   
2018-01-24 23:14:35.000000000 +0100
@@ -1278,9 +1278,9 @@
                 'storage_protocol': 'iSCSI',
                 'properties': {
                     'compression': {
-                        'title': 'Compression',
-                        'description': 'Enables compression.',
-                        'type': 'boolean'},
+                        u'title': u'Compression',
+                        u'description': u'Enables compression.',
+                        u'type': u'boolean'},
                 }
             }
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/v2/test_volumes.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/v2/test_volumes.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/v2/test_volumes.py    
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/v2/test_volumes.py    
2018-01-24 23:14:35.000000000 +0100
@@ -15,13 +15,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from cinderclient import api_versions
 from cinderclient.tests.unit import utils
 from cinderclient.tests.unit.v2 import fakes
 from cinderclient.v2.volumes import Volume
 
 cs = fakes.FakeClient()
-cs3 = fakes.FakeClient(api_versions.APIVersion('3.15'))
 
 
 class VolumesTest(utils.TestCase):
@@ -213,23 +211,23 @@
         self._assert_request_id(vol)
 
     def test_migrate(self):
-        v = cs3.volumes.get('1234')
+        v = cs.volumes.get('1234')
         self._assert_request_id(v)
-        vol = cs3.volumes.migrate_volume(v, 'dest', False, False)
-        cs3.assert_called('POST', '/volumes/1234/action',
-                          {'os-migrate_volume': {'host': 'dest',
-                                                 'force_host_copy': False,
+        vol = cs.volumes.migrate_volume(v, 'dest', False, False)
+        cs.assert_called('POST', '/volumes/1234/action',
+                         {'os-migrate_volume': {'host': 'dest',
+                                                'force_host_copy': False,
                                                 'lock_volume': False}})
         self._assert_request_id(vol)
 
     def test_migrate_with_lock_volume(self):
-        v = cs3.volumes.get('1234')
+        v = cs.volumes.get('1234')
         self._assert_request_id(v)
-        vol = cs3.volumes.migrate_volume(v, 'dest', False, True)
-        cs3.assert_called('POST', '/volumes/1234/action',
-                          {'os-migrate_volume': {'host': 'dest',
-                                                 'force_host_copy': False,
-                                                 'lock_volume': True}})
+        vol = cs.volumes.migrate_volume(v, 'dest', False, True)
+        cs.assert_called('POST', '/volumes/1234/action',
+                         {'os-migrate_volume': {'host': 'dest',
+                                                'force_host_copy': False,
+                                                'lock_volume': True}})
         self._assert_request_id(vol)
 
     def test_metadata_update_all(self):
@@ -262,19 +260,19 @@
         self._assert_request_id(vol)
 
     def test_volume_manage(self):
-        vol = cs3.volumes.manage('host1', {'k': 'v'})
+        vol = cs.volumes.manage('host1', {'k': 'v'})
         expected = {'host': 'host1', 'name': None, 'availability_zone': None,
                     'description': None, 'metadata': None, 'ref': {'k': 'v'},
                     'volume_type': None, 'bootable': False}
-        cs3.assert_called('POST', '/os-volume-manage', {'volume': expected})
+        cs.assert_called('POST', '/os-volume-manage', {'volume': expected})
         self._assert_request_id(vol)
 
     def test_volume_manage_bootable(self):
-        vol = cs3.volumes.manage('host1', {'k': 'v'}, bootable=True)
+        vol = cs.volumes.manage('host1', {'k': 'v'}, bootable=True)
         expected = {'host': 'host1', 'name': None, 'availability_zone': None,
                     'description': None, 'metadata': None, 'ref': {'k': 'v'},
                     'volume_type': None, 'bootable': True}
-        cs3.assert_called('POST', '/os-volume-manage', {'volume': expected})
+        cs.assert_called('POST', '/os-volume-manage', {'volume': expected})
         self._assert_request_id(vol)
 
     def test_volume_list_manageable(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/fakes.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/fakes.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/fakes.py   
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/fakes.py   
2018-01-24 23:14:35.000000000 +0100
@@ -145,6 +145,7 @@
                 'state': 'up',
                 'updated_at': datetime(2012, 10, 29, 13, 42, 2),
                 'cluster': 'cluster1',
+                'backend_state': 'up',
             },
             {
                 'id': 2,
@@ -155,6 +156,7 @@
                 'state': 'down',
                 'updated_at': datetime(2012, 9, 18, 8, 3, 38),
                 'cluster': 'cluster1',
+                'backend_state': 'down',
             },
             {
                 'id': 3,
@@ -174,6 +176,11 @@
         if not self.api_version.matches('3.7'):
             for svc in services:
                 del svc['cluster']
+
+        if not self.api_version.matches('3.49'):
+            for svc in services:
+                if svc['binary'] == 'cinder-volume':
+                    del svc['backend_state']
         return (200, {}, {'services': services})
 
     #
@@ -606,6 +613,17 @@
                                             }
                          }
 
+    def post_workers_cleanup(self, **kw):
+        response = {
+            'cleaning': [{'id': '1', 'cluster_name': 'cluster1',
+                          'host': 'host1', 'binary': 'binary'},
+                         {'id': '3', 'cluster_name': 'cluster1',
+                          'host': 'host3', 'binary': 'binary'}],
+            'unavailable': [{'id': '2', 'cluster_name': 'cluster2',
+                             'host': 'host2', 'binary': 'binary'}],
+        }
+        return 200, {}, response
+
     #
     # resource filters
     #
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/test_services.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/test_services.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/test_services.py   
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/test_services.py   
2018-01-24 23:14:35.000000000 +0100
@@ -79,3 +79,17 @@
                                       loaded=True)]
         # Since it will be sorted by the prefix we can compare them directly
         self.assertListEqual(expected, result)
+
+    def test_list_services_with_backend_state(self):
+        cs = fakes.FakeClient(api_version=api_versions.APIVersion('3.49'))
+        services_list = cs.services.list()
+        cs.assert_called('GET', '/os-services')
+        self.assertEqual(3, len(services_list))
+        for service in services_list:
+            self.assertIsInstance(service, services.Service)
+            # Make sure backend_state fields from v3.49 is present and not
+            # None
+            if service.binary == 'cinder-volume':
+                self.assertIsNotNone(getattr(service, 'backend_state',
+                                             None))
+        self._assert_request_id(services_list)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/test_shell.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/test_shell.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/test_shell.py      
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/test_shell.py      
2018-01-24 23:14:35.000000000 +0100
@@ -693,6 +693,11 @@
                          'manageable-list fakehost --detailed False')
         self.assert_called('GET', '/manageable_volumes?host=fakehost')
 
+    def test_volume_manageable_list_cluster(self):
+        self.run_command('--os-volume-api-version 3.17 '
+                         'manageable-list --cluster dest')
+        self.assert_called('GET', '/manageable_volumes/detail?cluster=dest')
+
     def test_snapshot_manageable_list(self):
         self.run_command('--os-volume-api-version 3.8 '
                          'snapshot-manageable-list fakehost')
@@ -708,6 +713,36 @@
                          'snapshot-manageable-list fakehost --detailed False')
         self.assert_called('GET', '/manageable_snapshots?host=fakehost')
 
+    def test_snapshot_manageable_list_cluster(self):
+        self.run_command('--os-volume-api-version 3.17 '
+                         'snapshot-manageable-list --cluster dest')
+        self.assert_called('GET', '/manageable_snapshots/detail?cluster=dest')
+
+    @ddt.data('', 'snapshot-')
+    def test_manageable_list_cluster_before_3_17(self, prefix):
+        self.assertRaises(exceptions.UnsupportedAttribute,
+                          self.run_command,
+                          '--os-volume-api-version 3.16 '
+                         '%smanageable-list --cluster dest' % prefix)
+
+    @mock.patch('cinderclient.shell.CinderClientArgumentParser.error')
+    @ddt.data('', 'snapshot-')
+    def test_manageable_list_mutual_exclusion(self, prefix, error_mock):
+        error_mock.side_effect = SystemExit
+        self.assertRaises(SystemExit,
+                          self.run_command,
+                          '--os-volume-api-version 3.17 '
+                         '%smanageable-list fakehost --cluster dest' % prefix)
+
+    @mock.patch('cinderclient.shell.CinderClientArgumentParser.error')
+    @ddt.data('', 'snapshot-')
+    def test_manageable_list_missing_required(self, prefix, error_mock):
+        error_mock.side_effect = SystemExit
+        self.assertRaises(SystemExit,
+                          self.run_command,
+                          '--os-volume-api-version 3.17 '
+                         '%smanageable-list' % prefix)
+
     def test_list_messages(self):
         self.run_command('--os-volume-api-version 3.3 message-list')
         self.assert_called('GET', '/messages')
@@ -1194,7 +1229,7 @@
                                'metadata': {'k1': 'v1', 'k2': 'v2'},
                                'bootable': bootable}}
         if cluster:
-            expected['cluster'] = cluster
+            expected['volume']['cluster'] = cluster
         self.assert_called_anytime('POST', '/os-volume-manage', body=expected)
 
     def test_volume_manage_before_3_16(self):
@@ -1206,3 +1241,23 @@
                           '--name foo --description bar --bootable '
                           '--volume-type baz --availability-zone az '
                           '--metadata k1=v1 k2=v2')
+
+    def test_worker_cleanup_before_3_24(self):
+        self.assertRaises(SystemExit,
+                          self.run_command,
+                          'work-cleanup fakehost')
+
+    def test_worker_cleanup(self):
+        self.run_command('--os-volume-api-version 3.24 '
+                         'work-cleanup --cluster clustername --host hostname '
+                         '--binary binaryname --is-up false --disabled true '
+                         '--resource-id uuid --resource-type Volume')
+        expected = {'cluster_name': 'clustername',
+                    'host': 'hostname',
+                    'binary': 'binaryname',
+                    'is_up': 'false',
+                    'disabled': 'true',
+                    'resource_id': 'uuid',
+                    'resource_type': 'Volume'}
+
+        self.assert_called('POST', '/workers/cleanup', body=expected)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/test_volumes.py 
new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/test_volumes.py
--- old/python-cinderclient-3.4.0/cinderclient/tests/unit/v3/test_volumes.py    
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/tests/unit/v3/test_volumes.py    
2018-01-24 23:14:35.000000000 +0100
@@ -104,6 +104,16 @@
         cs.volumes.summary(all_tenants=all_tenants)
         cs.assert_called('GET', url)
 
+    def test_volume_manage_cluster(self):
+        cs = fakes.FakeClient(api_versions.APIVersion('3.16'))
+        vol = cs.volumes.manage(None, {'k': 'v'}, cluster='cluster1')
+        expected = {'host': None, 'name': None, 'availability_zone': None,
+                    'description': None, 'metadata': None, 'ref': {'k': 'v'},
+                    'volume_type': None, 'bootable': False,
+                    'cluster': 'cluster1'}
+        cs.assert_called('POST', '/os-volume-manage', {'volume': expected})
+        self._assert_request_id(vol)
+
     def test_volume_list_manageable(self):
         cs = fakes.FakeClient(api_versions.APIVersion('3.8'))
         cs.volumes.list_manageable('host1', detailed=False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/v2/shell.py 
new/python-cinderclient-3.5.0/cinderclient/v2/shell.py
--- old/python-cinderclient-3.4.0/cinderclient/v2/shell.py      2018-01-08 
15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v2/shell.py      2018-01-24 
23:14:35.000000000 +0100
@@ -2375,7 +2375,8 @@
 
     prop = infos.pop('properties', None)
     utils.print_dict(infos, "Volume stats")
-    utils.print_dict(prop, "Backend properties")
+    utils.print_dict(prop, "Backend properties",
+                     formatters=sorted(prop.keys()))
 
 
 @utils.arg('volume',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/v2/volume_backups.py 
new/python-cinderclient-3.5.0/cinderclient/v2/volume_backups.py
--- old/python-cinderclient-3.4.0/cinderclient/v2/volume_backups.py     
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v2/volume_backups.py     
2018-01-24 23:15:04.000000000 +0100
@@ -55,6 +55,9 @@
         :param description: The description of the backup.
         :param incremental: Incremental backup.
         :param force: If True, allows an in-use volume to be backed up.
+        :param snapshot_id: The ID of the snapshot to backup. This should
+                            be a snapshot of the src volume, when specified,
+                            the new backup will be based on the snapshot.
         :rtype: :class:`VolumeBackup`
         """
         body = {'backup': {'volume_id': volume_id,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/v3/client.py 
new/python-cinderclient-3.5.0/cinderclient/v3/client.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/client.py     2018-01-08 
15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/client.py     2018-01-24 
23:14:35.000000000 +0100
@@ -42,6 +42,7 @@
 from cinderclient.v3 import volume_type_access
 from cinderclient.v3 import volume_types
 from cinderclient.v3 import volumes
+from cinderclient.v3 import workers
 
 
 class Client(object):
@@ -91,6 +92,7 @@
         self.transfers = volume_transfers.VolumeTransferManager(self)
         self.services = services.ServiceManager(self)
         self.clusters = clusters.ClusterManager(self)
+        self.workers = workers.WorkerManager(self)
         self.consistencygroups = consistencygroups.\
             ConsistencygroupManager(self)
         self.groups = groups.GroupManager(self)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/v3/groups.py 
new/python-cinderclient-3.5.0/cinderclient/v3/groups.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/groups.py     2018-01-08 
15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/groups.py     2018-01-24 
23:14:35.000000000 +0100
@@ -63,6 +63,7 @@
     """Manage :class:`Group` resources."""
     resource_class = Group
 
+    @api_versions.wraps('3.13')
     def create(self, group_type, volume_types, name=None,
                description=None, user_id=None,
                project_id=None, availability_zone=None):
@@ -96,6 +97,7 @@
         body = {'status': state} if state else {}
         return self._action('reset_status', group, body)
 
+    @api_versions.wraps('3.14')
     def create_from_src(self, group_snapshot_id, source_group_id,
                         name=None, description=None, user_id=None,
                         project_id=None):
@@ -123,6 +125,7 @@
             "/groups/action", body=body)
         return common_base.DictWithMeta(body['group'], resp)
 
+    @api_versions.wraps('3.13')
     def get(self, group_id, **kwargs):
         """Get a group.
 
@@ -139,6 +142,7 @@
         return self._get("/groups/%s" % group_id + query_string,
                          "group")
 
+    @api_versions.wraps('3.13')
     def list(self, detailed=True, search_opts=None, list_volume=False):
         """Lists all groups.
 
@@ -157,6 +161,7 @@
         return self._list("/groups%s%s" % (detail, query_string),
                           "groups")
 
+    @api_versions.wraps('3.13')
     def delete(self, group, delete_volumes=False):
         """Delete a group.
 
@@ -169,6 +174,7 @@
         resp, body = self.api.client.post(url, body=body)
         return common_base.TupleWithMeta((resp, body), resp)
 
+    @api_versions.wraps('3.13')
     def update(self, group, **kwargs):
         """Update the name or description for a group.
 
@@ -197,6 +203,7 @@
         resp, body = self.api.client.post(url, body=body)
         return common_base.TupleWithMeta((resp, body), resp)
 
+    @api_versions.wraps('3.38')
     def enable_replication(self, group):
         """Enables replication for a group.
 
@@ -208,6 +215,7 @@
         resp, body = self.api.client.post(url, body=body)
         return common_base.TupleWithMeta((resp, body), resp)
 
+    @api_versions.wraps('3.38')
     def disable_replication(self, group):
         """disables replication for a group.
 
@@ -219,6 +227,7 @@
         resp, body = self.api.client.post(url, body=body)
         return common_base.TupleWithMeta((resp, body), resp)
 
+    @api_versions.wraps('3.38')
     def failover_replication(self, group, allow_attached_volume=False,
                              secondary_backend_id=None):
         """fails over replication for a group.
@@ -238,6 +247,7 @@
         resp, body = self.api.client.post(url, body=body)
         return common_base.TupleWithMeta((resp, body), resp)
 
+    @api_versions.wraps('3.38')
     def list_replication_targets(self, group):
         """List replication targets for a group.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/v3/shell.py 
new/python-cinderclient-3.5.0/cinderclient/v3/shell.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/shell.py      2018-01-08 
15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/shell.py      2018-01-24 
23:14:35.000000000 +0100
@@ -1060,6 +1060,52 @@
     utils.print_dict(cluster.to_dict())
 
 
+@api_versions.wraps('3.24')
+@utils.arg('--cluster', metavar='<cluster-name>', default=None,
+           help='Cluster name. Default=None.')
+@utils.arg('--host', metavar='<hostname>', default=None,
+           help='Service host name. Default=None.')
+@utils.arg('--binary', metavar='<binary>', default=None,
+           help='Service binary. Default=None.')
+@utils.arg('--is-up', metavar='<True|true|False|false>', dest='is_up',
+           default=None, choices=('True', 'true', 'False', 'false'),
+           help='Filter by up/down status, if set to true services need to be'
+                ' up, if set to false services need to be down.  Default is '
+                'None, which means up/down status is ignored.')
+@utils.arg('--disabled', metavar='<True|true|False|false>', default=None,
+           choices=('True', 'true', 'False', 'false'),
+           help='Filter by disabled status. Default=None.')
+@utils.arg('--resource-id', metavar='<resource-id>', default=None,
+           help='UUID of a resource to cleanup. Default=None.')
+@utils.arg('--resource-type', metavar='<Volume|Snapshot>', default=None,
+           choices=('Volume', 'Snapshot'),
+           help='Type of resource to cleanup.')
+def do_work_cleanup(cs, args):
+    """Request cleanup of services with optional filtering."""
+    filters = dict(cluster_name=args.cluster, host=args.host,
+                   binary=args.binary, is_up=args.is_up,
+                   disabled=args.disabled, resource_id=args.resource_id,
+                   resource_type=args.resource_type)
+
+    filters = {k: v for k, v in filters.items() if v is not None}
+
+    cleaning, unavailable = cs.workers.clean(**filters)
+
+    columns = ('ID', 'Cluster Name', 'Host', 'Binary')
+
+    if cleaning:
+        print('Following services will be cleaned:')
+        utils.print_list(cleaning, columns)
+
+    if unavailable:
+        print('There are no alternative nodes to do cleanup for the following '
+              'services:')
+        utils.print_list(unavailable, columns)
+
+    if not (cleaning or unavailable):
+        print('No cleanable services matched cleanup criteria.')
+
+
 @utils.arg('host',
            metavar='<host>',
            help='Cinder host on which the existing volume resides; '
@@ -1139,10 +1185,20 @@
 
 
 @api_versions.wraps('3.8')
-@utils.arg('host',
-           metavar='<host>',
-           help='Cinder host on which to list manageable volumes; '
-                'takes the form: host@backend-name#pool')
+# NOTE(geguileo): host is positional but optional in order to maintain backward
+# compatibility even with mutually exclusive arguments.  If version is < 3.16
+# then only host positional argument will be possible, and since the
+# exclusive_arg group has required=True it will be required even if it's
+# optional.
+@utils.exclusive_arg('source', 'host', required=True, nargs='?',
+                     metavar='<host>',
+                     help='Cinder host on which to list manageable volumes; '
+                          'takes the form: host@backend-name#pool')
+@utils.exclusive_arg('source', '--cluster', required=True,
+                     metavar='CLUSTER',
+                     help='Cinder cluster on which to list manageable '
+                     'volumes; takes the form: cluster@backend-name#pool',
+                     start_version='3.17')
 @utils.arg('--detailed',
            metavar='<detailed>',
            default=True,
@@ -1174,9 +1230,11 @@
     """Lists all manageable volumes."""
     # pylint: disable=function-redefined
     detailed = strutils.bool_from_string(args.detailed)
+    cluster = getattr(args, 'cluster', None)
     volumes = cs.volumes.list_manageable(host=args.host, detailed=detailed,
                                          marker=args.marker, limit=args.limit,
-                                         offset=args.offset, sort=args.sort)
+                                         offset=args.offset, sort=args.sort,
+                                         cluster=cluster)
     columns = ['reference', 'size', 'safe_to_manage']
     if detailed:
         columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
@@ -1597,14 +1655,25 @@
     # so as not to add the column when the extended ext is not enabled.
     if result and hasattr(result[0], 'disabled_reason'):
         columns.append("Disabled Reason")
+    if cs.api_version.matches('3.49'):
+        columns.extend(["Backend State"])
     utils.print_list(result, columns)
 
 
 @api_versions.wraps('3.8')
-@utils.arg('host',
-           metavar='<host>',
-           help='Cinder host on which to list manageable snapshots; '
-                'takes the form: host@backend-name#pool')
+# NOTE(geguileo): host is positional but optional in order to maintain backward
+# compatibility even with mutually exclusive arguments.  If version is < 3.16
+# then only host positional argument will be possible, and since the
+# exclusive_arg group has required=True it will be required even if it's
+# optional.
+@utils.exclusive_arg('source', 'host', required=True, nargs='?',
+                     metavar='<host>',
+                     help='Cinder host on which to list manageable snapshots; '
+                     'takes the form: host@backend-name#pool')
+@utils.exclusive_arg('source', '--cluster', required=True,
+                     help='Cinder cluster on which to list manageable '
+                     'snapshots; takes the form: cluster@backend-name#pool',
+                     start_version='3.17')
 @utils.arg('--detailed',
            metavar='<detailed>',
            default=True,
@@ -1636,12 +1705,14 @@
     """Lists all manageable snapshots."""
     # pylint: disable=function-redefined
     detailed = strutils.bool_from_string(args.detailed)
+    cluster = getattr(args, 'cluster', None)
     snapshots = cs.volume_snapshots.list_manageable(host=args.host,
                                                     detailed=detailed,
                                                     marker=args.marker,
                                                     limit=args.limit,
                                                     offset=args.offset,
-                                                    sort=args.sort)
+                                                    sort=args.sort,
+                                                    cluster=cluster)
     columns = ['reference', 'size', 'safe_to_manage', 'source_reference']
     if detailed:
         columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/v3/volume_backups.py 
new/python-cinderclient-3.5.0/cinderclient/v3/volume_backups.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/volume_backups.py     
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/volume_backups.py     
2018-01-24 23:15:04.000000000 +0100
@@ -52,6 +52,9 @@
         :param description: The description of the backup.
         :param incremental: Incremental backup.
         :param force: If True, allows an in-use volume to be backed up.
+        :param snapshot_id: The ID of the snapshot to backup. This should
+                            be a snapshot of the src volume, when specified,
+                            the new backup will be based on the snapshot.
         :rtype: :class:`VolumeBackup`
         """
         body = {'backup': {'volume_id': volume_id,
@@ -78,6 +81,9 @@
         :param incremental: Incremental backup.
         :param force: If True, allows an in-use volume to be backed up.
         :param metadata: Key Value pairs
+        :param snapshot_id: The ID of the snapshot to backup. This should
+                            be a snapshot of the src volume, when specified,
+                            the new backup will be based on the snapshot.
         :rtype: :class:`VolumeBackup`
         """
         # pylint: disable=function-redefined
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/cinderclient/v3/volume_snapshots.py 
new/python-cinderclient-3.5.0/cinderclient/v3/volume_snapshots.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/volume_snapshots.py   
2018-01-08 15:00:26.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/volume_snapshots.py   
2018-01-24 23:14:35.000000000 +0100
@@ -65,10 +65,11 @@
                             description=description, metadata=metadata)
 
     def list_manageable(self, host, detailed=True, marker=None, limit=None,
-                        offset=None, sort=None):
+                        offset=None, sort=None, cluster=None):
         return self.manager.list_manageable(host, detailed=detailed,
                                             marker=marker, limit=limit,
-                                            offset=offset, sort=sort)
+                                            offset=offset, sort=sort,
+                                            cluster=cluster)
 
     def unmanage(self, snapshot):
         """Unmanage a snapshot."""
@@ -212,11 +213,12 @@
                 }
         return self._create('/os-snapshot-manage', body, 'snapshot')
 
-    @api_versions.wraps("3.8")
+    @api_versions.wraps('3.8')
     def list_manageable(self, host, detailed=True, marker=None, limit=None,
-                        offset=None, sort=None):
+                        offset=None, sort=None, cluster=None):
+        search_opts = {'cluster': cluster} if cluster else {'host': host}
         url = self._build_list_url("manageable_snapshots", detailed=detailed,
-                                   search_opts={'host': host}, marker=marker,
+                                   search_opts=search_opts, marker=marker,
                                    limit=limit, offset=offset, sort=sort)
         return self._list(url, "manageable-snapshots")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/v3/volumes.py 
new/python-cinderclient-3.5.0/cinderclient/v3/volumes.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/volumes.py    2018-01-08 
15:00:37.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/volumes.py    2018-01-24 
23:14:35.000000000 +0100
@@ -258,14 +258,15 @@
                            'bootable': bootable
                            }}
         if self.api_version.matches('3.16') and cluster:
-            body['cluster'] = cluster
+            body['volume']['cluster'] = cluster
         return self._create('/os-volume-manage', body, 'volume')
 
-    @api_versions.wraps("3.8")
+    @api_versions.wraps('3.8')
     def list_manageable(self, host, detailed=True, marker=None, limit=None,
-                        offset=None, sort=None):
+                        offset=None, sort=None, cluster=None):
+        search_opts = {'cluster': cluster} if cluster else {'host': host}
         url = self._build_list_url("manageable_volumes", detailed=detailed,
-                                   search_opts={'host': host}, marker=marker,
+                                   search_opts=search_opts, marker=marker,
                                    limit=limit, offset=offset, sort=sort)
         return self._list(url, "manageable-volumes")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/cinderclient/v3/workers.py 
new/python-cinderclient-3.5.0/cinderclient/v3/workers.py
--- old/python-cinderclient-3.4.0/cinderclient/v3/workers.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/python-cinderclient-3.5.0/cinderclient/v3/workers.py    2018-01-24 
23:14:35.000000000 +0100
@@ -0,0 +1,44 @@
+# Copyright (c) 2016 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    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.
+
+"""
+Interface to workers API
+"""
+from cinderclient.apiclient import base as common_base
+from cinderclient import base
+
+
+class Service(base.Resource):
+    def __repr__(self):
+        return "<Service (%s): %s in cluster %s>" % (self.id, self.host,
+                                                     self.cluster_name or '-')
+
+    @classmethod
+    def list_factory(cls, mngr, elements):
+        return [cls(mngr, element, loaded=True) for element in elements]
+
+
+class WorkerManager(base.Manager):
+    base_url = '/workers'
+
+    def clean(self, **filters):
+        url = self.base_url + '/cleanup'
+        resp, body = self.api.client.post(url, body=filters)
+
+        cleaning = Service.list_factory(self, body['cleaning'])
+        unavailable = Service.list_factory(self, body['unavailable'])
+
+        result = common_base.TupleWithMeta((cleaning, unavailable), resp)
+        return result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-cinderclient-3.4.0/doc/requirements.txt 
new/python-cinderclient-3.5.0/doc/requirements.txt
--- old/python-cinderclient-3.4.0/doc/requirements.txt  2018-01-08 
15:00:37.000000000 +0100
+++ new/python-cinderclient-3.5.0/doc/requirements.txt  2018-01-24 
23:14:35.000000000 +0100
@@ -4,4 +4,4 @@
 # These are needed for docs generation
 openstackdocstheme>=1.17.0 # Apache-2.0
 reno>=2.5.0 # Apache-2.0
-sphinx>=1.6.2 # BSD
+sphinx!=1.6.6,>=1.6.2 # BSD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/python_cinderclient.egg-info/PKG-INFO 
new/python-cinderclient-3.5.0/python_cinderclient.egg-info/PKG-INFO
--- old/python-cinderclient-3.4.0/python_cinderclient.egg-info/PKG-INFO 
2018-01-08 15:02:53.000000000 +0100
+++ new/python-cinderclient-3.5.0/python_cinderclient.egg-info/PKG-INFO 
2018-01-24 23:18:18.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-cinderclient
-Version: 3.4.0
+Version: 3.5.0
 Summary: OpenStack Block Storage API Client Library
 Home-page: https://docs.openstack.org/python-cinderclient/latest/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/python_cinderclient.egg-info/SOURCES.txt 
new/python-cinderclient-3.5.0/python_cinderclient.egg-info/SOURCES.txt
--- old/python-cinderclient-3.4.0/python_cinderclient.egg-info/SOURCES.txt      
2018-01-08 15:02:53.000000000 +0100
+++ new/python-cinderclient-3.5.0/python_cinderclient.egg-info/SOURCES.txt      
2018-01-24 23:18:19.000000000 +0100
@@ -184,6 +184,7 @@
 cinderclient/v3/volume_type_access.py
 cinderclient/v3/volume_types.py
 cinderclient/v3/volumes.py
+cinderclient/v3/workers.py
 cinderclient/v3/contrib/__init__.py
 cinderclient/v3/contrib/list_extensions.py
 doc/.gitignore
@@ -219,6 +220,7 @@
 releasenotes/notes/bug-1713082-fb9276eed70f7e3b.yaml
 releasenotes/notes/cinder-poll-4f92694cc7eb657a.yaml
 releasenotes/notes/cluster_commands-dca50e89c9d53cd2.yaml
+releasenotes/notes/cluster_list_manageable-40c02489b2c95d55.yaml
 releasenotes/notes/cluster_migration_manage-31144d67bbfdb739.yaml
 releasenotes/notes/deprecate-allow-multiattach-2213a100c65a95c1.yaml
 releasenotes/notes/do-not-reset-volume-status-ae8e28132d7bfacd.yaml
@@ -232,6 +234,7 @@
 releasenotes/notes/replication-group-v3-api-022900ce6bf8feba.yaml
 releasenotes/notes/return-request-id-to-caller-78d27f33f0048405.yaml
 releasenotes/notes/revert-to-snapshot-er4598df88aq5918.yaml
+releasenotes/notes/service_cleanup_cmd-cac85b697bc22af1.yaml
 releasenotes/notes/service_dynamic_log-bd81d93c73fc1570.yaml
 releasenotes/notes/start-using-reno-18001103a6719c13.yaml
 releasenotes/notes/support---os-key-option-72ba2fd4880736ac.yaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/python_cinderclient.egg-info/pbr.json 
new/python-cinderclient-3.5.0/python_cinderclient.egg-info/pbr.json
--- old/python-cinderclient-3.4.0/python_cinderclient.egg-info/pbr.json 
2018-01-08 15:02:53.000000000 +0100
+++ new/python-cinderclient-3.5.0/python_cinderclient.egg-info/pbr.json 
2018-01-24 23:18:18.000000000 +0100
@@ -1 +1 @@
-{"git_version": "36a2f4b", "is_release": true}
\ No newline at end of file
+{"git_version": "1de605c", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/releasenotes/notes/cluster_list_manageable-40c02489b2c95d55.yaml
 
new/python-cinderclient-3.5.0/releasenotes/notes/cluster_list_manageable-40c02489b2c95d55.yaml
--- 
old/python-cinderclient-3.4.0/releasenotes/notes/cluster_list_manageable-40c02489b2c95d55.yaml
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/python-cinderclient-3.5.0/releasenotes/notes/cluster_list_manageable-40c02489b2c95d55.yaml
      2018-01-24 23:14:35.000000000 +0100
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Cinder ``manageable-list`` and ``snapshot-manageable-list`` commands now
+    accept ``--cluster`` argument to specify the backend we want to list for
+    microversion 3.17 and higher.  This argument and the ``host`` positional
+    argument are mutually exclusive.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-cinderclient-3.4.0/releasenotes/notes/service_cleanup_cmd-cac85b697bc22af1.yaml
 
new/python-cinderclient-3.5.0/releasenotes/notes/service_cleanup_cmd-cac85b697bc22af1.yaml
--- 
old/python-cinderclient-3.4.0/releasenotes/notes/service_cleanup_cmd-cac85b697bc22af1.yaml
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/python-cinderclient-3.5.0/releasenotes/notes/service_cleanup_cmd-cac85b697bc22af1.yaml
  2018-01-24 23:14:35.000000000 +0100
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    New ``work-cleanup`` command to trigger server cleanups by other nodes
+    within a cluster on Active-Active deployments on microversion 3.24 and
+    higher.


Reply via email to