Hello community, here is the log from the commit of package python-manilaclient for openSUSE:Factory checked in at 2015-12-21 12:04:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-manilaclient (Old) and /work/SRC/openSUSE:Factory/.python-manilaclient.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-manilaclient" Changes: -------- --- /work/SRC/openSUSE:Factory/python-manilaclient/python-manilaclient.changes 2015-10-30 13:42:39.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-manilaclient.new/python-manilaclient.changes 2015-12-21 12:04:02.000000000 +0100 @@ -1,0 +2,11 @@ +Mon Nov 16 14:12:08 UTC 2015 - tbecht...@suse.com + +- update to 1.5.0: + * Add Keystone v3 API support + * Incorrect help of export_path for the manage utility + * Updated from global requirements + * Fix args parsing for quota-class-update + * Change Manilaclient to use --os-region-name param + * Updated from global requirements + +------------------------------------------------------------------- Old: ---- python-manilaclient-1.4.0.tar.gz New: ---- python-manilaclient-1.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-manilaclient.spec ++++++ --- /var/tmp/diff_new_pack.SgZLIc/_old 2015-12-21 12:04:03.000000000 +0100 +++ /var/tmp/diff_new_pack.SgZLIc/_new 2015-12-21 12:04:03.000000000 +0100 @@ -19,7 +19,7 @@ %define component manilaclient Name: python-%{component} -Version: 1.4.0 +Version: 1.5.0 Release: 0 Summary: Openstack shared file system service (Manila) API Client License: Apache-2.0 ++++++ python-manilaclient-1.4.0.tar.gz -> python-manilaclient-1.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/AUTHORS new/python-manilaclient-1.5.0/AUTHORS --- old/python-manilaclient-1.4.0/AUTHORS 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/AUTHORS 2015-10-19 21:25:25.000000000 +0200 @@ -28,6 +28,7 @@ Yulia Portnova <yportn...@mirantis.com> bswartz <b...@swartzlander.org> cFouts <fch...@netapp.com> +nidhimittalhada <nidhimitta...@gmail.com> vik <vik@ubuntu.(none)> vponomaryov <vponomar...@mirantis.com> zhongjun <jun.zhong...@huawei.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/ChangeLog new/python-manilaclient-1.5.0/ChangeLog --- old/python-manilaclient-1.4.0/ChangeLog 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/ChangeLog 2015-10-19 21:25:25.000000000 +0200 @@ -1,6 +1,16 @@ CHANGES ======= +1.5.0 +----- + +* Add Keystone v3 API support +* Incorrect help of export_path for the manage utility +* Updated from global requirements +* Fix args parsing for quota-class-update +* Change Manilaclient to use --os-region-name param +* Updated from global requirements + 1.4.0 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/PKG-INFO new/python-manilaclient-1.5.0/PKG-INFO --- old/python-manilaclient-1.4.0/PKG-INFO 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/PKG-INFO 2015-10-19 21:25:25.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: python-manilaclient -Version: 1.4.0 +Version: 1.5.0 Summary: Client library for OpenStack Manila API. Home-page: http://www.openstack.org/ Author: OpenStack Contributors diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/shell.py new/python-manilaclient-1.5.0/manilaclient/shell.py --- old/python-manilaclient-1.4.0/manilaclient/shell.py 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/shell.py 2015-10-19 21:24:31.000000000 +0200 @@ -139,6 +139,13 @@ action='store_true', help='Delete cached password and auth token.') + parser.add_argument('--os-user-id', + metavar='<auth-user-id>', + default=cliutils.env('OS_USER_ID'), + help=('Defaults to env [OS_USER_ID].')) + parser.add_argument('--os_user_id', + help=argparse.SUPPRESS) + parser.add_argument('--os-username', metavar='<auth-user-name>', default=cliutils.env('OS_USERNAME', @@ -163,6 +170,16 @@ parser.add_argument('--os_tenant_name', help=argparse.SUPPRESS) + parser.add_argument('--os-project-name', + metavar='<auth-project-name>', + default=cliutils.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-tenant-id', metavar='<auth-tenant-id>', default=cliutils.env('OS_TENANT_ID', @@ -171,6 +188,46 @@ parser.add_argument('--os_tenant_id', help=argparse.SUPPRESS) + parser.add_argument('--os-project-id', + metavar='<auth-project-id>', + default=cliutils.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.add_argument('--os_project_id', + help=argparse.SUPPRESS) + + parser.add_argument('--os-user-domain-id', + metavar='<auth-user-domain-id>', + default=cliutils.env('OS_USER_DOMAIN_ID'), + help=('OpenStack user domain ID. ' + 'Defaults to 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=cliutils.env('OS_USER_DOMAIN_NAME'), + help=('OpenStack user domain name. ' + 'Defaults to env[OS_USER_DOMAIN_NAME].')) + parser.add_argument('--os_user_domain_name', + help=argparse.SUPPRESS) + + parser.add_argument('--os-project-domain-id', + metavar='<auth-project-domain-id>', + default=cliutils.env('OS_PROJECT_DOMAIN_ID'), + help='Defaults to env[OS_PROJECT_DOMAIN_ID].') + parser.add_argument('--os_project_domain_id', + help=argparse.SUPPRESS) + + parser.add_argument('--os-project-domain-name', + metavar='<auth-project-domain-name>', + default=cliutils.env('OS_PROJECT_DOMAIN_NAME'), + help='Defaults to env[OS_PROJECT_DOMAIN_NAME].') + parser.add_argument('--os_project_domain_name', + help=argparse.SUPPRESS) + parser.add_argument('--os-auth-url', metavar='<auth-url>', default=cliutils.env('OS_AUTH_URL', @@ -246,6 +303,13 @@ default=0, help='Number of retries.') + parser.add_argument('--os-cert', + metavar='<certificate>', + default=cliutils.env('OS_CERT'), + help='Defaults to env[OS_CERT].') + parser.add_argument('--os_cert', + help=argparse.SUPPRESS) + return parser def get_subcommand_parser(self, version): @@ -386,12 +450,18 @@ (os_username, os_password, os_tenant_name, os_auth_url, os_region_name, os_tenant_id, endpoint_type, insecure, service_type, service_name, share_service_name, - cacert, os_cache, os_reset_cache) = ( + cacert, os_cache, os_reset_cache, os_user_id, os_user_domain_id, + os_user_domain_name, os_project_domain_id, os_project_domain_name, + os_project_name, os_project_id, os_cert) = ( args.os_username, args.os_password, args.os_tenant_name, args.os_auth_url, args.os_region_name, args.os_tenant_id, args.endpoint_type, args.insecure, args.service_type, args.service_name, args.share_service_name, - args.os_cacert, args.os_cache, args.os_reset_cache) + args.os_cacert, args.os_cache, args.os_reset_cache, + args.os_user_id, args.os_user_domain_id, args.os_user_domain_name, + args.os_project_domain_id, args.os_project_domain_name, + args.os_project_name, args.os_project_id, args.os_cert, + ) if share_service_name: service_name = share_service_name @@ -403,29 +473,19 @@ service_type = DEFAULT_MANILA_SERVICE_TYPE service_type = cliutils.get_service_type(args.func) or service_type - # FIXME(usrleon): Here should be restrict for project id same as - # for os_username or os_password but for compatibility it is not. - - if not cliutils.isunauthenticated(args.func): - if not os_username: - raise exc.CommandError( - "You must provide a username " - "via either --os-username or env[OS_USERNAME]") - - if not (os_tenant_name or os_tenant_id): - raise exc.CommandError("You must provide a tenant_id " - "via either --os-tenant-id or " - "env[OS_TENANT_ID]") - - if not os_auth_url: - raise exc.CommandError( - "You must provide an auth url " - "via either --os-auth-url or env[OS_AUTH_URL]") - - if not (os_tenant_name or os_tenant_id): + if not (os_tenant_name or os_tenant_id or os_project_name or + os_project_id): raise exc.CommandError( - "You must provide a tenant_id " - "via either --os-tenant-id or env[OS_TENANT_ID]") + "You must provide a tenant_name, tenant_id, " + "project_id or project_name (with " + "project_domain_name or project_domain_id) via " + "--os-tenant-name (env[OS_TENANT_NAME]), " + "--os-tenant-id (env[OS_TENANT_ID]), " + "--os-project-id (env[OS_PROJECT_ID]), " + "--os-project-name (env[OS_PROJECT_NAME]), " + "--os-project-domain-id (env[OS_PROJECT_DOMAIN_ID]) and " + "--os-project-domain-name (env[OS_PROJECT_DOMAIN_NAME])." + ) if not os_auth_url: raise exc.CommandError( @@ -434,11 +494,12 @@ self.cs = client.Client(options.os_share_api_version, username=os_username, - api_key=os_password, - project_name=os_tenant_name, + password=os_password, + project_name=os_project_name or os_tenant_name, auth_url=os_auth_url, - insecure=insecure, region_name=os_region_name, - tenant_id=os_tenant_id, + insecure=insecure, + region_name=os_region_name, + tenant_id=os_project_id or os_tenant_id, endpoint_type=endpoint_type, extensions=self.extensions, service_type=service_type, @@ -448,7 +509,13 @@ cacert=cacert, use_keyring=os_cache, force_new_token=os_reset_cache, - api_version=options.os_share_api_version) + api_version=options.os_share_api_version, + user_id=os_user_id, + user_domain_id=os_user_domain_id, + user_domain_name=os_user_domain_name, + project_domain_id=os_project_domain_id, + project_domain_name=os_project_domain_name, + cert=os_cert) args.func(self.cs, args) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/tests/unit/test_shell.py new/python-manilaclient-1.5.0/manilaclient/tests/unit/test_shell.py --- old/python-manilaclient-1.4.0/manilaclient/tests/unit/test_shell.py 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/tests/unit/test_shell.py 2015-10-19 21:24:31.000000000 +0200 @@ -13,16 +13,20 @@ import re import sys +import ddt import fixtures +import mock from six import moves from testtools import matchers +from manilaclient.common import constants from manilaclient import exceptions from manilaclient import shell from manilaclient.tests.unit import utils -class ShellTest(utils.TestCase): +@ddt.ddt +class OpenstackManilaShellTest(utils.TestCase): FAKE_ENV = { 'OS_USERNAME': 'username', @@ -32,11 +36,9 @@ } # Patch os.environ to avoid required auth info. - def setUp(self): - super(ShellTest, self).setUp() - for var in self.FAKE_ENV: - self.useFixture(fixtures.EnvironmentVariable(var, - self.FAKE_ENV[var])) + def set_env_vars(self, env_vars): + for k, v in env_vars.items(): + self.useFixture(fixtures.EnvironmentVariable(k, v)) def shell(self, argstr): orig = sys.stdout @@ -54,6 +56,70 @@ return out + @ddt.data( + {}, + {'OS_AUTH_URL': 'http://foo.bar'}, + {'OS_AUTH_URL': 'http://foo.bar', 'OS_USERNAME': 'foo'}, + {'OS_AUTH_URL': 'http://foo.bar', 'OS_USERNAME': 'foo_user', + 'OS_PASSWORD': 'foo_password'}, + {'OS_TENANT_NAME': 'foo_tenant', 'OS_USERNAME': 'foo_user', + 'OS_PASSWORD': 'foo_password'}, + ) + def test_main_failure(self, env_vars): + self.set_env_vars(env_vars) + with mock.patch.object(shell, 'client') as mock_client: + self.assertRaises(exceptions.CommandError, self.shell, 'list') + self.assertFalse(mock_client.Client.called) + + def test_main_success(self): + env_vars = { + 'OS_AUTH_URL': 'http://foo.bar', + 'OS_USERNAME': 'foo_username', + 'OS_USER_ID': 'foo_user_id', + 'OS_PASSWORD': 'foo_password', + 'OS_TENANT_NAME': 'foo_tenant', + 'OS_TENANT_ID': 'foo_tenant_id', + 'OS_PROJECT_NAME': 'foo_project', + 'OS_PROJECT_ID': 'foo_project_id', + 'OS_PROJECT_DOMAIN_ID': 'foo_project_domain_id', + 'OS_PROJECT_DOMAIN_NAME': 'foo_project_domain_name', + 'OS_PROJECT_DOMAIN_ID': 'foo_project_domain_id', + 'OS_USER_DOMAIN_NAME': 'foo_user_domain_name', + 'OS_USER_DOMAIN_ID': 'foo_user_domain_id', + 'OS_CERT': 'foo_cert', + } + self.set_env_vars(env_vars) + with mock.patch.object(shell, 'client') as mock_client: + + self.shell('list') + + mock_client.Client.assert_called_once_with( + constants.MAX_API_VERSION, + username=env_vars['OS_USERNAME'], + password=env_vars['OS_PASSWORD'], + project_name=env_vars['OS_PROJECT_NAME'], + auth_url=env_vars['OS_AUTH_URL'], + insecure=False, + region_name='', + tenant_id=env_vars['OS_PROJECT_ID'], + endpoint_type='publicURL', + extensions=mock.ANY, + service_type='sharev2', + service_name='', + retries=0, + http_log_debug=False, + cacert=None, + use_keyring=False, + force_new_token=False, + api_version=constants.MAX_API_VERSION, + user_id=env_vars['OS_USER_ID'], + user_domain_id=env_vars['OS_USER_DOMAIN_ID'], + user_domain_name=env_vars['OS_USER_DOMAIN_NAME'], + project_domain_id=env_vars['OS_PROJECT_DOMAIN_ID'], + project_domain_name=env_vars['OS_PROJECT_DOMAIN_NAME'], + cert=env_vars['OS_CERT'], + ) + def test_help_unknown_command(self): self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo') @@ -79,3 +145,20 @@ for r in required: self.assertThat(help_text, matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE)) + + def test_common_args_in_help_message(self): + expected_args = ( + '--version', '', '--debug', '--os-cache', '--os-reset-cache', + '--os-user-id', '--os-username', '--os-password', + '--os-tenant-name', '--os-project-name', '--os-tenant-id', + '--os-project-id', '--os-user-domain-id', '--os-user-domain-name', + '--os-project-domain-id', '--os-project-domain-name', + '--os-auth-url', '--os-region-name', '--service-type', + '--service-name', '--share-service-name', '--endpoint-type', + '--os-share-api-version', '--os-cacert', '--retries', '--os-cert', + ) + + help_text = self.shell('help') + + for expected_arg in expected_args: + self.assertIn(expected_arg, help_text) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/tests/unit/utils.py new/python-manilaclient-1.5.0/manilaclient/tests/unit/utils.py --- old/python-manilaclient-1.4.0/manilaclient/tests/unit/utils.py 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/tests/unit/utils.py 2015-10-19 21:24:31.000000000 +0200 @@ -13,6 +13,7 @@ import os import fixtures +import mock import requests import testtools @@ -33,6 +34,20 @@ stderr = self.useFixture(fixtures.StringStream('stderr')).stream self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) + def mock_object(self, obj, attr_name, new_attr=None, **kwargs): + """Mock an object attribute. + + Use python mock to mock an object attribute + Mocks the specified objects attribute with the given value. + Automatically performs 'addCleanup' for the mock. + """ + if not new_attr: + new_attr = mock.Mock() + patcher = mock.patch.object(obj, attr_name, new_attr, **kwargs) + patcher.start() + self.addCleanup(patcher.stop) + return new_attr + class TestResponse(requests.Response): """Class used to wrap requests.Response. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/tests/unit/v1/test_client.py new/python-manilaclient-1.5.0/manilaclient/tests/unit/v1/test_client.py --- old/python-manilaclient-1.4.0/manilaclient/tests/unit/v1/test_client.py 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/tests/unit/v1/test_client.py 2015-10-19 21:24:31.000000000 +0200 @@ -12,7 +12,8 @@ import uuid -from keystoneclient import session +import ddt +import mock from manilaclient.common import constants from manilaclient import exceptions @@ -20,14 +21,22 @@ from manilaclient.v1 import client +@ddt.ddt class ClientTest(utils.TestCase): + def setUp(self): + super(self.__class__, self).setUp() + self.catalog = { + 'share': [ + {'region': 'TestRegion', 'publicURL': 'http://1.2.3.4'}, + ], + } def test_adapter_properties(self): # sample of properties, there are many more retries = 3 base_url = uuid.uuid4().hex - s = session.Session() + s = client.session.Session() c = client.Client(session=s, api_version=constants.MAX_API_VERSION, service_catalog_url=base_url, retries=retries, input_auth_token='token') @@ -41,7 +50,7 @@ input_auth_token="token") def test_auth_via_token_and_session(self): - s = session.Session() + s = client.session.Session() base_url = uuid.uuid4().hex c = client.Client(input_auth_token='token', service_catalog_url=base_url, session=s, @@ -59,3 +68,229 @@ self.assertIsNotNone(c.client) self.assertIsNone(c.keystone_client) + + @mock.patch.object(client.Client, '_get_keystone_client', mock.Mock()) + def test_valid_region_name(self): + self.mock_object(client.httpclient, 'HTTPClient') + kc = client.Client._get_keystone_client.return_value + kc.service_catalog = mock.Mock() + kc.service_catalog.get_endpoints = mock.Mock(return_value=self.catalog) + c = client.Client(api_version=constants.MAX_API_VERSION, + region_name='TestRegion') + self.assertTrue(client.Client._get_keystone_client.called) + kc.service_catalog.get_endpoints.assert_called_once_with('share') + client.httpclient.HTTPClient.assert_called_once_with( + 'http://1.2.3.4', + mock.ANY, + 'python-manilaclient', + insecure=False, + cacert=None, + timeout=None, + retries=None, + http_log_debug=False, + api_version=constants.MAX_API_VERSION) + self.assertIsNotNone(c.client) + + @mock.patch.object(client.Client, '_get_keystone_client', mock.Mock()) + def test_nonexistent_region_name(self): + kc = client.Client._get_keystone_client.return_value + kc.service_catalog = mock.Mock() + kc.service_catalog.get_endpoints = mock.Mock(return_value=self.catalog) + self.assertRaises(RuntimeError, client.Client, + api_version=constants.MAX_API_VERSION, + region_name='FakeRegion') + + self.assertTrue(client.Client._get_keystone_client.called) + kc.service_catalog.get_endpoints.assert_called_once_with('share') + + @mock.patch.object(client.Client, '_get_keystone_client', mock.Mock()) + def test_regions_with_same_name(self): + self.mock_object(client.httpclient, 'HTTPClient') + catalog = { + 'share': [ + {'region': 'FirstRegion', 'publicURL': 'http://1.2.3.4'}, + {'region': 'secondregion', 'publicURL': 'http://1.1.1.1'}, + {'region': 'SecondRegion', 'publicURL': 'http://2.2.2.2'}, + ], + } + kc = client.Client._get_keystone_client.return_value + kc.service_catalog = mock.Mock() + kc.service_catalog.get_endpoints = mock.Mock(return_value=catalog) + c = client.Client(api_version=constants.MAX_API_VERSION, + region_name='SecondRegion') + self.assertTrue(client.Client._get_keystone_client.called) + kc.service_catalog.get_endpoints.assert_called_once_with('share') + client.httpclient.HTTPClient.assert_called_once_with( + 'http://2.2.2.2', + mock.ANY, + 'python-manilaclient', + insecure=False, + cacert=None, + timeout=None, + retries=None, + http_log_debug=False, + api_version=constants.MAX_API_VERSION) + self.assertIsNotNone(c.client) + + def _get_client_args(self, **kwargs): + client_args = { + 'auth_url': 'both', + 'api_version': constants.MAX_API_VERSION, + 'username': 'fake_username', + 'service_type': 'sharev2', + 'region_name': 'SecondRegion', + 'input_auth_token': None, + 'session': None, + 'service_catalog_url': None, + 'user_id': 'foo_user_id', + 'user_domain_name': 'foo_user_domain_name', + 'user_domain_id': 'foo_user_domain_id', + 'project_name': 'foo_project_name', + 'project_domain_name': 'foo_project_domain_name', + 'project_domain_id': 'foo_project_domain_id', + 'endpoint_type': 'publicUrl', + 'cert': 'foo_cert', + } + client_args.update(kwargs) + return client_args + + @ddt.data( + {'auth_url': 'only_v3', 'api_key': 'password_backward_compat', + 'endpoint_type': 'publicURL', 'project_id': 'foo_tenant_project_id'}, + {'password': 'renamed_api_key', 'endpoint_type': 'public', + 'tenant_id': 'foo_tenant_project_id'}, + ) + def test_client_init_no_session_no_auth_token_v3(self, kwargs): + def fake_url_for(version): + if version == 'v3.0': + return 'url_v3.0' + elif version == 'v2.0' and self.auth_url == 'both': + return 'url_v2.0' + else: + return None + + self.mock_object(client.httpclient, 'HTTPClient') + self.mock_object(client.ks_client, 'Client') + self.mock_object(client.discover, 'Discover') + self.mock_object(client.session, 'Session') + client_args = self._get_client_args(**kwargs) + self.auth_url = client_args['auth_url'] + catalog = { + 'share': [ + {'region': 'SecondRegion', 'region_id': 'SecondRegion', + 'url': 'http://4.4.4.4', 'interface': 'public', + }, + ], + 'sharev2': [ + {'region': 'FirstRegion', 'interface': 'public', + 'region_id': 'SecondRegion', 'url': 'http://1.1.1.1'}, + {'region': 'secondregion', 'interface': 'public', + 'region_id': 'SecondRegion', 'url': 'http://2.2.2.2'}, + {'region': 'SecondRegion', 'interface': 'internal', + 'region_id': 'SecondRegion', 'url': 'http://3.3.3.1'}, + {'region': 'SecondRegion', 'interface': 'public', + 'region_id': 'SecondRegion', 'url': 'http://3.3.3.3'}, + {'region': 'SecondRegion', 'interface': 'admin', + 'region_id': 'SecondRegion', 'url': 'http://3.3.3.2'}, + ], + } + client.discover.Discover.return_value.url_for.side_effect = ( + fake_url_for) + client.ks_client.Client.return_value.auth_token.return_value = ( + 'fake_token') + mocked_ks_client = client.ks_client.Client.return_value + mocked_ks_client.service_catalog.get_endpoints.return_value = catalog + + client.Client(**client_args) + + client.httpclient.HTTPClient.assert_called_once_with( + 'http://3.3.3.3', mock.ANY, 'python-manilaclient', insecure=False, + cacert=None, timeout=None, retries=None, http_log_debug=False, + api_version=constants.MAX_API_VERSION) + client.ks_client.Client.assert_called_once_with( + version=(3, 0), auth_url='url_v3.0', + username=client_args['username'], + password=client_args.get('password', client_args.get('api_key')), + user_id=client_args['user_id'], + user_domain_name=client_args['user_domain_name'], + user_domain_id=client_args['user_domain_id'], + project_id=client_args.get('tenant_id', + client_args.get('project_id')), + project_name=client_args['project_name'], + project_domain_name=client_args['project_domain_name'], + project_domain_id=client_args['project_domain_id'], + region_name=client_args['region_name'], + ) + mocked_ks_client.service_catalog.get_endpoints.assert_called_once_with( + client_args['service_type']) + mocked_ks_client.authenticate.assert_called_once_with() + + @ddt.data( + {'auth_url': 'only_v2', 'api_key': 'foo', 'project_id': 'bar'}, + {'password': 'foo', 'tenant_id': 'bar'}, + ) + def test_client_init_no_session_no_auth_token_v2(self, kwargs): + self.mock_object(client.httpclient, 'HTTPClient') + self.mock_object(client.ks_client, 'Client') + self.mock_object(client.discover, 'Discover') + self.mock_object(client.session, 'Session') + client_args = self._get_client_args(**kwargs) + self.auth_url = client_args['auth_url'] + catalog = { + 'share': [ + {'region': 'SecondRegion', 'publicUrl': 'http://4.4.4.4'}, + ], + 'sharev2': [ + {'region': 'FirstRegion', 'publicUrl': 'http://1.1.1.1'}, + {'region': 'secondregion', 'publicUrl': 'http://2.2.2.2'}, + {'region': 'SecondRegion', 'internalUrl': 'http://3.3.3.1', + 'publicUrl': 'http://3.3.3.3', 'adminUrl': 'http://3.3.3.2'}, + ], + } + client.discover.Discover.return_value.url_for.side_effect = ( + lambda v: 'url_v2.0' if v == 'v2.0' else None) + client.ks_client.Client.return_value.auth_token.return_value = ( + 'fake_token') + mocked_ks_client = client.ks_client.Client.return_value + mocked_ks_client.service_catalog.get_endpoints.return_value = catalog + + client.Client(**client_args) + + client.httpclient.HTTPClient.assert_called_once_with( + 'http://3.3.3.3', mock.ANY, 'python-manilaclient', insecure=False, + cacert=None, timeout=None, retries=None, http_log_debug=False, + api_version=constants.MAX_API_VERSION) + client.ks_client.Client.assert_called_once_with( + version=(2, 0), auth_url='url_v2.0', + username=client_args['username'], + password=client_args.get('password', client_args.get('api_key')), + tenant_id=client_args.get('tenant_id', + client_args.get('project_id')), + tenant_name=client_args['project_name'], + region_name=client_args['region_name'], cert=client_args['cert'], + use_keyring=False, force_new_token=False, stale_duration=300) + mocked_ks_client.service_catalog.get_endpoints.assert_called_once_with( + client_args['service_type']) + mocked_ks_client.authenticate.assert_called_once_with() + + @mock.patch.object(client.ks_client, 'Client', mock.Mock()) + @mock.patch.object(client.discover, 'Discover', mock.Mock()) + @mock.patch.object(client.session, 'Session', mock.Mock()) + def test_client_init_no_session_no_auth_token_endpoint_not_found(self): + self.mock_object(client.httpclient, 'HTTPClient') + client_args = self._get_client_args( + auth_urli='fake_url', + password='foo_password', + tenant_id='foo_tenant_id') + client.discover.Discover.return_value.url_for.return_value = None + mocked_ks_client = client.ks_client.Client.return_value + + self.assertRaises( + exceptions.CommandError, client.Client, **client_args) + + self.assertTrue(client.session.Session.called) + self.assertTrue(client.discover.Discover.called) + self.assertFalse(client.httpclient.HTTPClient.called) + self.assertFalse(client.ks_client.Client.called) + self.assertFalse(mocked_ks_client.service_catalog.get_endpoints.called) + self.assertFalse(mocked_ks_client.authenticate.called) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/tests/unit/v1/test_shell.py new/python-manilaclient-1.5.0/manilaclient/tests/unit/v1/test_shell.py --- old/python-manilaclient-1.4.0/manilaclient/tests/unit/v1/test_shell.py 2015-09-18 16:22:37.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/tests/unit/v1/test_shell.py 2015-10-19 21:24:31.000000000 +0200 @@ -99,6 +99,69 @@ def assert_called_anytime(self, method, url, body=None): return self.shell.cs.assert_called_anytime(method, url, body) + @ddt.data( + {'serviceCatalog': [{'name': 'foo', 'endpoints': ['bar']}]}, + {'catalog': [{'name': 'foo', 'endpoints': ['bar']}]}, + {'serviceCatalog': [{'name': 'foo', 'endpoints': ['bar']}], + 'catalog': 'fake'}, + ) + def test_do_endpoints(self, catalog): + cs = type('Fake', (object, ), {'keystone_client': type( + 'FakeKeystoneClient', (object, ), { + 'service_catalog': type('FakeCatalog', (object, ), { + 'catalog': catalog})})}) + + with mock.patch.object( + shell_v1.cliutils, 'print_dict') as mock_print_dict: + shell_v1.do_endpoints(cs, ('no', 'args')) + + mock_print_dict.assert_has_calls([ + mock.call('bar', 'foo'), + ]) + + @ddt.data( + {'version': 'v3', + 'user': 'foo_user', + 'issued_at': 'foo_issued_at', + 'expires_at': 'foo_expires', + 'auth_token': 'foo_ids', + 'audit_ids': 'foo_audit_ids', + 'project': 'foo_tenant_project', + 'redundant_key': 'should not be used', + }, + {'version': 'v2.0', + 'user': 'foo_user', + 'token': { + 'issued_at': 'foo_issued_at', + 'expires': 'foo_expires', + 'id': 'foo_ids', + 'audit_ids': 'foo_audit_ids', + 'tenant': 'foo_tenant_project', + }, + }, + ) + def test_do_credentials(self, catalog): + cs = type('Fake', (object, ), {'keystone_client': type( + 'FakeKeystoneClient', (object, ), { + 'service_catalog': type('FakeCatalog', (object, ), { + 'catalog': catalog})})}) + expected_call_data = { + 'issued_at': 'foo_issued_at', + 'expires': 'foo_expires', + 'id': 'foo_ids', + 'audit_ids': 'foo_audit_ids', + 'tenant': 'foo_tenant_project', + } + + with mock.patch.object( + shell_v1.cliutils, 'print_dict') as mock_print_dict: + shell_v1.do_credentials(cs, ('no', 'args')) + + mock_print_dict.assert_has_calls([ + mock.call('foo_user', 'User Credentials'), + mock.call(expected_call_data, 'Token'), + ]) + def test_list(self): self.run_command('list') # NOTE(jdg): we default to detail currently @@ -1440,3 +1503,29 @@ self.run_command('cg-snapshot-delete --force fake-cg') self.assert_called('POST', '/cgsnapshots/1234/action', {'os-force_delete': None}) + + @ddt.data( + {'--shares': 5}, + {'--snapshots': 5}, + {'--gigabytes': 5}, + {'--snapshot-gigabytes': 5}, + {'--snapshot_gigabytes': 5}, + {'--share-networks': 5}, + {'--share_networks': 5}, + {'--shares': 5, + '--snapshots': 5, + '--gigabytes': 5, + '--snapshot-gigabytes': 5, + '--share-networks': 5}) + def test_quota_class_update(self, data): + cmd = 'quota-class-update test' + expected = dict() + for k, v in data.items(): + cmd += ' %(arg)s %(val)s' % {'arg': k, 'val': v} + expected[k[2:].replace('-', '_')] = v + expected['class_name'] = 'test' + expected = dict(quota_class_set=expected) + + self.run_command(cmd) + self.assert_called('PUT', '/os-quota-class-sets/test', + body=expected) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/v1/client.py new/python-manilaclient-1.5.0/manilaclient/v1/client.py --- old/python-manilaclient-1.4.0/manilaclient/v1/client.py 2015-09-18 16:22:37.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/v1/client.py 2015-10-19 21:24:31.000000000 +0200 @@ -13,8 +13,9 @@ import warnings from keystoneclient import adapter -from keystoneclient.v2_0 import client as keystone_client_v2 -from keystoneclient.v3 import client as keystone_client_v3 +from keystoneclient import client as ks_client +from keystoneclient import discover +from keystoneclient import session import six from manilaclient.common import constants @@ -72,7 +73,41 @@ service_catalog_url=None, user_agent='python-manilaclient', use_keyring=False, force_new_token=False, cached_token_lifetime=300, - api_version=constants.V1_API_VERSION, **kwargs): + api_version=constants.V1_API_VERSION, + user_id=None, + user_domain_id=None, + user_domain_name=None, + project_domain_id=None, + project_domain_name=None, + cert=None, + password=None, + **kwargs): + + self.username = username + self.password = password or api_key + self.tenant_id = tenant_id or project_id + self.tenant_name = project_name + + self.user_id = user_id + self.project_id = project_id or tenant_id + self.project_name = project_name + self.user_domain_id = user_domain_id + self.user_domain_name = user_domain_name + self.project_domain_id = project_domain_id + self.project_domain_name = project_domain_name + + self.endpoint_type = endpoint_type + self.auth_url = auth_url + self.region_name = region_name + + self.cacert = cacert + self.cert = cert + self.insecure = insecure + + self.use_keyring = use_keyring + self.force_new_token = force_new_token + self.cached_token_lifetime = cached_token_lifetime + service_name = kwargs.get("share_service_name", service_name) def check_deprecated_arguments(): @@ -80,7 +115,8 @@ 'share_service_name': 'service_name', 'proxy_tenant_id': None, 'proxy_token': None, - 'os_cache': 'use_keyring' + 'os_cache': 'use_keyring', + 'api_key': 'password', } for arg, replacement in six.iteritems(deprecated): @@ -124,15 +160,7 @@ input_auth_token = self.keystone_client.session.get_token(auth) else: - self.keystone_client = self._get_keystone_client( - username=username, - api_key=api_key, - auth_url=auth_url, - project_id=self.project_id, - project_name=project_name, - use_keyring=use_keyring, - force_new_token=force_new_token, - stale_duration=cached_token_lifetime) + self.keystone_client = self._get_keystone_client() input_auth_token = self.keystone_client.auth_token if not input_auth_token: @@ -145,12 +173,18 @@ elif not service_catalog_url: catalog = self.keystone_client.service_catalog.get_endpoints( service_type) - - if service_type in catalog: - for e_type, endpoint in catalog.get(service_type)[0].items(): - if str(e_type).lower() == str(endpoint_type).lower(): - service_catalog_url = endpoint - break + for catalog_entry in catalog.get(service_type, []): + if (catalog_entry.get("interface") == ( + endpoint_type.lower().split("url")[0]) or + catalog_entry.get(endpoint_type)): + if (region_name and not region_name == ( + catalog_entry.get( + "region", + catalog_entry.get("region_id")))): + continue + service_catalog_url = catalog_entry.get( + "url", catalog_entry.get(endpoint_type)) + break if not service_catalog_url: raise RuntimeError("Could not find Manila endpoint in catalog") @@ -196,33 +230,6 @@ if extension.manager_class: setattr(self, extension.name, extension.manager_class(self)) - def _get_keystone_client(self, username=None, api_key=None, auth_url=None, - token=None, project_id=None, project_name=None, - use_keyring=False, force_new_token=False, - stale_duration=0): - if not auth_url: - raise RuntimeError("No auth url specified") - - if not getattr(self, "keystone_client", None): - imported_client = (keystone_client_v2 if "v2.0" in auth_url - else keystone_client_v3) - - self.keystone_client = imported_client.Client( - username=username, - password=api_key, - token=token, - tenant_id=project_id, - tenant_name=project_name, - auth_url=auth_url, - endpoint=auth_url, - use_keyring=use_keyring, - force_new_token=force_new_token, - stale_duration=stale_duration) - - self.keystone_client.authenticate() - - return self.keystone_client - def authenticate(self): """Authenticate against the server. @@ -235,3 +242,54 @@ warnings.warn("authenticate() method is deprecated. " "Client automatically makes authentication call " "in the constructor.") + + def _get_keystone_client(self): + # First create a Keystone session + if self.insecure: + verify = False + else: + verify = self.cacert or True + ks_session = session.Session(verify=verify, cert=self.cert) + + # Discover the supported keystone versions using the given url + ks_discover = discover.Discover( + session=ks_session, auth_url=self.auth_url) + + # Inspect the auth_url to see the supported version. If both v3 and v2 + # are supported, then use the highest version if possible. + v2_auth_url = ks_discover.url_for('v2.0') + v3_auth_url = ks_discover.url_for('v3.0') + + if v3_auth_url: + keystone_client = ks_client.Client( + version=(3, 0), + auth_url=v3_auth_url, + username=self.username, + password=self.password, + user_id=self.user_id, + user_domain_name=self.user_domain_name, + user_domain_id=self.user_domain_id, + project_id=self.project_id or self.tenant_id, + project_name=self.project_name, + project_domain_name=self.project_domain_name, + project_domain_id=self.project_domain_id, + region_name=self.region_name) + elif v2_auth_url: + keystone_client = ks_client.Client( + version=(2, 0), + auth_url=v2_auth_url, + username=self.username, + password=self.password, + tenant_id=self.tenant_id, + tenant_name=self.tenant_name, + region_name=self.region_name, + cert=self.cert, + use_keyring=self.use_keyring, + force_new_token=self.force_new_token, + stale_duration=self.cached_token_lifetime) + else: + raise exceptions.CommandError( + 'Unable to determine the Keystone version to authenticate ' + 'with using the given auth_url.') + keystone_client.authenticate() + return keystone_client diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/v1/quota_classes.py new/python-manilaclient-1.5.0/manilaclient/v1/quota_classes.py --- old/python-manilaclient-1.4.0/manilaclient/v1/quota_classes.py 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/v1/quota_classes.py 2015-10-19 21:24:31.000000000 +0200 @@ -40,6 +40,7 @@ shares=None, gigabytes=None, snapshots=None, + snapshot_gigabytes=None, share_networks=None): body = { @@ -48,6 +49,7 @@ 'shares': shares, 'snapshots': snapshots, 'gigabytes': gigabytes, + 'snapshot_gigabytes': snapshot_gigabytes, 'share_networks': share_networks, } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/manilaclient/v1/shell.py new/python-manilaclient-1.5.0/manilaclient/v1/shell.py --- old/python-manilaclient-1.4.0/manilaclient/v1/shell.py 2015-09-18 16:22:37.000000000 +0200 +++ new/python-manilaclient-1.5.0/manilaclient/v1/shell.py 2015-10-19 21:24:31.000000000 +0200 @@ -201,7 +201,7 @@ def do_endpoints(cs, args): """Discover endpoints that get returned from the authenticate services.""" catalog = cs.keystone_client.service_catalog.catalog - for e in catalog['serviceCatalog']: + for e in catalog.get('serviceCatalog', catalog.get('catalog')): cliutils.print_dict(e['endpoints'][0], e['name']) @@ -209,7 +209,17 @@ """Show user credentials returned from auth.""" catalog = cs.keystone_client.service_catalog.catalog cliutils.print_dict(catalog['user'], "User Credentials") - cliutils.print_dict(catalog['token'], "Token") + if not catalog['version'] == 'v3': + data = catalog['token'] + else: + data = { + 'issued_at': catalog['issued_at'], + 'expires': catalog['expires_at'], + 'id': catalog['auth_token'], + 'audit_ids': catalog['audit_ids'], + 'tenant': catalog['project'], + } + cliutils.print_dict(data, "Token") _quota_resources = [ 'shares', @@ -366,7 +376,7 @@ @cliutils.arg( - 'class-name', + 'class_name', metavar='<class-name>', help='Name of quota class to set the quotas for.') @cliutils.arg( @@ -397,9 +407,11 @@ help='New value for the "snapshot_gigabytes" quota.') @cliutils.arg( '--share-networks', + '--share_networks', # alias metavar='<share-networks>', type=int, default=None, + action='single_alias', help='New value for the "share_networks" quota.') @cliutils.service_type('sharev2') def do_quota_class_update(cs, args): @@ -607,7 +619,7 @@ metavar='<export_path>', type=str, help='Share export path, NFS share such as: 10.0.0.1:/foo_path, ' - 'CIFS share such as: \\10.0.0.1\foo_name_of_cifs_share') + 'CIFS share such as: \\\\10.0.0.1\\foo_name_of_cifs_share') @cliutils.arg( '--name', metavar='<name>', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/python_manilaclient.egg-info/PKG-INFO new/python-manilaclient-1.5.0/python_manilaclient.egg-info/PKG-INFO --- old/python-manilaclient-1.4.0/python_manilaclient.egg-info/PKG-INFO 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/python_manilaclient.egg-info/PKG-INFO 2015-10-19 21:25:25.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: python-manilaclient -Version: 1.4.0 +Version: 1.5.0 Summary: Client library for OpenStack Manila API. Home-page: http://www.openstack.org/ Author: OpenStack Contributors diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/python_manilaclient.egg-info/pbr.json new/python-manilaclient-1.5.0/python_manilaclient.egg-info/pbr.json --- old/python-manilaclient-1.4.0/python_manilaclient.egg-info/pbr.json 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/python_manilaclient.egg-info/pbr.json 2015-10-19 21:25:25.000000000 +0200 @@ -1 +1 @@ -{"is_release": true, "git_version": "0bbd214"} \ No newline at end of file +{"git_version": "997cc43", "is_release": true} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/python_manilaclient.egg-info/requires.txt new/python-manilaclient-1.5.0/python_manilaclient.egg-info/requires.txt --- old/python-manilaclient-1.4.0/python_manilaclient.egg-info/requires.txt 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/python_manilaclient.egg-info/requires.txt 2015-10-19 21:25:25.000000000 +0200 @@ -1,4 +1,4 @@ -pbr<2.0,>=1.6 +pbr>=1.6 argparse iso8601>=0.1.9 oslo.config>=2.3.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/requirements.txt new/python-manilaclient-1.5.0/requirements.txt --- old/python-manilaclient-1.4.0/requirements.txt 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/requirements.txt 2015-10-19 21:24:31.000000000 +0200 @@ -3,7 +3,7 @@ # process, which may cause wedges in the gate later. # pbr should be first -pbr<2.0,>=1.6 +pbr>=1.6 argparse iso8601>=0.1.9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/setup.cfg new/python-manilaclient-1.5.0/setup.cfg --- old/python-manilaclient-1.4.0/setup.cfg 2015-09-18 16:23:34.000000000 +0200 +++ new/python-manilaclient-1.5.0/setup.cfg 2015-10-19 21:25:25.000000000 +0200 @@ -43,6 +43,6 @@ [egg_info] tag_svn_revision = 0 -tag_date = 0 tag_build = +tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/setup.py new/python-manilaclient-1.5.0/setup.py --- old/python-manilaclient-1.4.0/setup.py 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/setup.py 2015-10-19 21:24:31.000000000 +0200 @@ -25,5 +25,5 @@ pass setuptools.setup( - setup_requires=['pbr>=1.3'], + setup_requires=['pbr>=1.8'], pbr=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-manilaclient-1.4.0/test-requirements.txt new/python-manilaclient-1.5.0/test-requirements.txt --- old/python-manilaclient-1.4.0/test-requirements.txt 2015-09-18 16:22:36.000000000 +0200 +++ new/python-manilaclient-1.5.0/test-requirements.txt 2015-10-19 21:24:31.000000000 +0200 @@ -13,7 +13,7 @@ ordereddict oslosphinx>=2.5.0 # Apache-2.0 sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 -tempest-lib>=0.6.1 +tempest-lib>=0.9.0 testrepository>=0.0.18 testtools>=1.4.0 python-openstackclient>=1.5.0