diff -Nru python-keystoneclient-1.6.0/bandit.yaml python-keystoneclient-1.7.1/bandit.yaml --- python-keystoneclient-1.6.0/bandit.yaml 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-1.7.1/bandit.yaml 2015-09-09 04:34:24.000000000 +0000 @@ -0,0 +1,134 @@ +# optional: after how many files to update progress +#show_progress_every: 100 + +# optional: plugins directory name +#plugins_dir: 'plugins' + +# optional: plugins discovery name pattern +plugin_name_pattern: '*.py' + +# optional: terminal escape sequences to display colors +#output_colors: +# DEFAULT: '\033[0m' +# HEADER: '\033[95m' +# INFO: '\033[94m' +# WARN: '\033[93m' +# ERROR: '\033[91m' + +# optional: log format string +#log_format: "[%(module)s]\t%(levelname)s\t%(message)s" + +# globs of files which should be analyzed +include: + - '*.py' + - '*.pyw' + +# a list of strings, which if found in the path will cause files to be excluded +# for example /tests/ - to remove all all files in tests directory +exclude_dirs: + - '/tests/' + +profiles: + keystone_conservative: + include: + - blacklist_calls + - blacklist_imports + - request_with_no_cert_validation + - exec_used + - set_bad_file_permissions + - subprocess_popen_with_shell_equals_true + - linux_commands_wildcard_injection + - ssl_with_bad_version + + + keystone_verbose: + include: + - blacklist_calls + - blacklist_imports + - request_with_no_cert_validation + - exec_used + - set_bad_file_permissions + - hardcoded_tmp_directory + - subprocess_popen_with_shell_equals_true + - any_other_function_with_shell_equals_true + - linux_commands_wildcard_injection + - ssl_with_bad_version + - ssl_with_bad_defaults + +blacklist_calls: + bad_name_sets: + - pickle: + qualnames: [pickle.loads, pickle.load, pickle.Unpickler, + cPickle.loads, cPickle.load, cPickle.Unpickler] + message: "Pickle library appears to be in use, possible security issue." + - marshal: + qualnames: [marshal.load, marshal.loads] + message: "Deserialization with the marshal module is possibly dangerous." + - md5: + qualnames: [hashlib.md5] + message: "Use of insecure MD5 hash function." + - mktemp_q: + qualnames: [tempfile.mktemp] + message: "Use of insecure and deprecated function (mktemp)." + - eval: + qualnames: [eval] + message: "Use of possibly insecure function - consider using safer ast.literal_eval." + - mark_safe: + names: [mark_safe] + message: "Use of mark_safe() may expose cross-site scripting vulnerabilities and should be reviewed." + - httpsconnection: + qualnames: [httplib.HTTPSConnection] + message: "Use of HTTPSConnection does not provide security, see https://wiki.openstack.org/wiki/OSSN/OSSN-0033" + - yaml_load: + qualnames: [yaml.load] + message: "Use of unsafe yaml load. Allows instantiation of arbitrary objects. Consider yaml.safe_load()." + - urllib_urlopen: + qualnames: [urllib.urlopen, urllib.urlretrieve, urllib.URLopener, urllib.FancyURLopener, urllib2.urlopen, urllib2.Request] + message: "Audit url open for permitted schemes. Allowing use of file:/ or custom schemes is often unexpected." + +shell_injection: + # Start a process using the subprocess module, or one of its wrappers. + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, + subprocess.check_output, utils.execute, utils.execute_with_timeout] + # Start a process with a function vulnerable to shell injection. + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, + popen2.popen2, popen2.popen3, popen2.popen4, popen2.Popen3, + popen2.Popen4, commands.getoutput, commands.getstatusoutput] + # Start a process with a function that is not vulnerable to shell injection. + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv,os.execve, + os.execvp, os.execvpe, os.spawnl, os.spawnle, os.spawnlp, + os.spawnlpe, os.spawnv, os.spawnve, os.spawnvp, os.spawnvpe, + os.startfile] + +blacklist_imports: + bad_import_sets: + - telnet: + imports: [telnetlib] + level: ERROR + message: "Telnet is considered insecure. Use SSH or some other encrypted protocol." + +hardcoded_password: + word_list: "wordlist/default-passwords" + +ssl_with_bad_version: + bad_protocol_versions: + - 'PROTOCOL_SSLv2' + - 'SSLv2_METHOD' + - 'SSLv23_METHOD' + - 'PROTOCOL_SSLv3' # strict option + - 'PROTOCOL_TLSv1' # strict option + - 'SSLv3_METHOD' # strict option + - 'TLSv1_METHOD' # strict option + +password_config_option_not_marked_secret: + function_names: + - oslo.config.cfg.StrOpt + - oslo_config.cfg.StrOpt + +execute_with_run_as_root_equals_true: + function_names: + - ceilometer.utils.execute + - cinder.utils.execute + - neutron.agent.linux.utils.execute + - nova.utils.execute + - nova.utils.trycmd diff -Nru python-keystoneclient-1.6.0/debian/changelog python-keystoneclient-1.7.1/debian/changelog --- python-keystoneclient-1.6.0/debian/changelog 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/changelog 2015-10-05 12:02:50.000000000 +0000 @@ -1,11 +1,41 @@ +python-keystoneclient (1:1.7.1-1ubuntu2) wily; urgency=medium + + * d/control: Drop python(3)-bandit and bandit as they're not needed + to run unit tests. + + -- Corey Bryant Mon, 05 Oct 2015 08:02:08 -0400 + +python-keystoneclient (1:1.7.1-1ubuntu1) wily; urgency=medium + + * d/control: Drop python(3)-pysaml2 as it's not needed. + + -- Corey Bryant Fri, 02 Oct 2015 12:09:10 -0400 + +python-keystoneclient (1:1.7.1-1) experimental; urgency=medium + + * New upstream release. + * d/control: Align (build-)depends with upstream. + * d/p/fix-dictionary-iteration-python3-test.patch: Dropped. Fixed upstream. + * d/p/fix-assertRaisesRegex-python3-tests.patch: Dropped. Fixed release. + * d/p/fix-key-iteration.patch: Dropped. Fixed upstream. + * d/p/oauth-use-actual-request-headers.patch: Dropped. Fixed upstream. + * d/control: Add python3-crypto, python3-coverage, python3-hacking to BD's. + * d/p/fix-test-deprecations.patch: Fix tests to handle deprecations. + + -- Corey Bryant Fri, 25 Sep 2015 10:06:55 -0400 + python-keystoneclient (1:1.6.0-2) experimental; urgency=medium + [ Corey Bryant ] * d/p/fix-key-iteration.patch: Iterate over copy of session.adapters keys. * d/p/fix-1368545.patch: Change http_connect_timeout to IntOpt. (LP: #1368545) * d/p/oauth-use-actual-request-headers.patch: Make OAuth testcase use actual request headers. - -- Corey Bryant Wed, 12 Aug 2015 09:30:59 -0400 + [ Thomas Goirand ] + * Build-depends on python-memcache (>= 1.56) and pysaml2 (>= 3.0.0). + + -- Thomas Goirand Sun, 06 Sep 2015 22:01:47 +0000 python-keystoneclient (1:1.6.0-1) experimental; urgency=medium diff -Nru python-keystoneclient-1.6.0/debian/control python-keystoneclient-1.7.1/debian/control --- python-keystoneclient-1.6.0/debian/control 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/control 2015-10-05 12:02:04.000000000 +0000 @@ -8,67 +8,70 @@ dh-python, openstack-pkg-tools, python-all, - python-pbr (>= 0.11), + python-pbr (>= 1.6), python-setuptools, python3-all, - python3-pbr (>= 0.11), + python3-pbr (>= 1.6), python-sphinx, Build-Depends-Indep: memcached, python-babel, python-coverage, python-crypto, - python-fixtures, + python-debtcollector, + python-fixtures (>= 1.3.1), python-hacking (>= 0.10.0), python-iso8601, python-keyring, python-lxml, - python-memcache, - python-mock, + python-memcache (>= 1.56), + python-mock (>= 1.3), python-mox3, python-netaddr (>= 0.7.12), python-oauthlib, - python-oslo.config (>= 1:1.11.0), + python-oslo.config (>= 1:2.3.0), python-oslo.i18n (>= 1.5.0), python-oslo.serialization (>= 1.4.0), - python-oslo.utils (>= 1.4.0), + python-oslo.utils (>= 2.0.0), python-oslosphinx (>= 2.5.0), - python-oslotest (>= 1.5.1), + python-oslotest (>= 1.10.0), python-prettytable, -# python-pysaml2, python-requests (>= 2.5.2), python-requests-mock (>= 0.6.0), python-six (>= 1.9.0), - python-stevedore (>= 1.3.0), - python-tempest-lib (>= 0.5.0), + python-stevedore (>= 1.5.0), + python-tempest-lib (>= 0.6.1), python-testresources, - python-testtools, + python-testtools (>= 1.4.0), python-webob, python3-babel, - python3-fixtures, + python3-crypto, + python3-coverage, + python3-debtcollector, + python3-fixtures (>= 1.3.1), python3-iso8601, + python3-hacking (>= 0.10.0), python3-keyring, python3-lxml, - python3-memcache (>= 1.54+20150423+git+48e882719c-1~), - python3-mock, + python3-memcache (>= 1.56), + python3-mock (>= 1.3), python3-mox3, python3-netaddr (>= 0.7.12), python3-oauthlib, - python3-oslo.config (>= 1:1.11.0), + python3-oslo.config (>= 1:2.3.0), python3-oslo.i18n (>= 1.5.0), python3-oslo.serialization (>= 1.4.0), - python3-oslo.utils (>= 1.4.0), - python3-oslotest (>= 1.5.1), + python3-oslo.utils (>= 2.0.0), + python3-oslotest (>= 1.10.0), python3-pep8, python3-prettytable, -# python3-pysaml2, python3-requests (>= 2.5.2), python3-requests-mock (>= 0.6.0), python3-six (>= 1.9.0), - python3-stevedore (>= 1.3.0), + python3-stevedore (>= 1.5.0), python3-subunit, - python3-tempest-lib (>= 0.5.0), + python3-tempest-lib (>= 0.6.1), python3-testresources, - python3-testtools, + python3-testtools (>= 1.4.0), python3-webob, subunit, testrepository, @@ -81,18 +84,19 @@ Package: python-keystoneclient Architecture: all Depends: python-babel, + python-debtcollector, python-iso8601, python-keyring, python-netaddr (>= 0.7.12), - python-oslo.config (>= 1:1.11.0), + python-oslo.config (>= 1:2.3.0), python-oslo.i18n (>= 1.5.0), python-oslo.serialization (>= 1.4.0), - python-oslo.utils (>= 1.4.0), - python-pbr (>= 0.11), + python-oslo.utils (>= 2.0.0), + python-pbr (>= 1.6), python-prettytable, python-requests (>= 2.5.2), python-six (>= 1.9.0), - python-stevedore (>= 1.3.0), + python-stevedore (>= 1.5.0), ${misc:Depends}, ${python:Depends}, Description: client library for the OpenStack Keystone API - Python 2.x @@ -115,18 +119,19 @@ Package: python3-keystoneclient Architecture: all Depends: python3-babel, + python3-debtcollector, python3-iso8601, python3-keyring, python3-netaddr (>= 0.7.12), - python3-oslo.config (>= 1:1.11.0), + python3-oslo.config (>= 1:2.3.0), python3-oslo.i18n (>= 1.5.0), python3-oslo.serialization (>= 1.4.0), - python3-oslo.utils (>= 1.4.0), - python3-pbr (>= 0.11), + python3-oslo.utils (>= 2.0.0), + python3-pbr (>= 1.6), python3-prettytable, python3-requests (>= 2.5.2), python3-six (>= 1.9.0), - python3-stevedore (>= 1.3.0), + python3-stevedore (>= 1.5.0), ${misc:Depends}, ${python3:Depends}, Description: client library for the OpenStack Keystone API - Python 3.x diff -Nru python-keystoneclient-1.6.0/debian/patches/fix-1368545.patch python-keystoneclient-1.7.1/debian/patches/fix-1368545.patch --- python-keystoneclient-1.6.0/debian/patches/fix-1368545.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/fix-1368545.patch 2015-10-02 16:08:56.000000000 +0000 @@ -12,9 +12,11 @@ Origin: upstream, https://review.openstack.org/#/c/126543 Bug-Ubuntu: https://bugs.launchpad.net/keystonemiddleware/+bug/1368545 ---- python-keystoneclient-0.7.1.orig/keystoneclient/middleware/auth_token.py -+++ python-keystoneclient-0.7.1/keystoneclient/middleware/auth_token.py -@@ -212,7 +212,7 @@ opts = [ +Index: python-keystoneclient/keystoneclient/middleware/auth_token.py +=================================================================== +--- python-keystoneclient.orig/keystoneclient/middleware/auth_token.py ++++ python-keystoneclient/keystoneclient/middleware/auth_token.py +@@ -235,7 +235,7 @@ opts = [ help='Do not handle authorization requests within the' ' middleware, but delegate the authorization decision to' ' downstream WSGI components'), diff -Nru python-keystoneclient-1.6.0/debian/patches/fix-assertRaisesRegex-python3-tests.patch python-keystoneclient-1.7.1/debian/patches/fix-assertRaisesRegex-python3-tests.patch --- python-keystoneclient-1.6.0/debian/patches/fix-assertRaisesRegex-python3-tests.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/fix-assertRaisesRegex-python3-tests.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -From 2a032a5f3777b7c388561104fa94b58231d4619e Mon Sep 17 00:00:00 2001 -From: Corey Bryant -Date: Fri, 5 Jun 2015 09:41:06 -0400 -Subject: [PATCH] Use python-six shim for assertRaisesRegex/p - -Python2 uses assertRaisesRegexp while Python3 uses assertRaisesRegex. -Use the compatability shim in six for this: -https://pythonhosted.org/six/#unittest-assertions - -Change-Id: I28ce94207567e0b3c28c634119757a1d68e955f2 -Closes-Bug: #1462370 ---- - keystoneclient/tests/unit/test_session.py | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/keystoneclient/tests/unit/test_session.py b/keystoneclient/tests/unit/test_session.py -index e0b6fb5..0b69ca4 100644 ---- a/keystoneclient/tests/unit/test_session.py -+++ b/keystoneclient/tests/unit/test_session.py -@@ -244,10 +244,11 @@ class SessionTests(utils.TestCase): - # The exception should contain the URL and details about the SSL error - msg = _('SSL exception connecting to %(url)s: %(error)s') % { - 'url': self.TEST_URL, 'error': error} -- self.assertRaisesRegex(exceptions.SSLError, -- msg, -- session.get, -- self.TEST_URL) -+ six.assertRaisesRegex(self, -+ exceptions.SSLError, -+ msg, -+ session.get, -+ self.TEST_URL) - - - class RedirectTests(utils.TestCase): --- -2.1.4 - diff -Nru python-keystoneclient-1.6.0/debian/patches/fix-dictionary-iteration-python3-test.patch python-keystoneclient-1.7.1/debian/patches/fix-dictionary-iteration-python3-test.patch --- python-keystoneclient-1.6.0/debian/patches/fix-dictionary-iteration-python3-test.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/fix-dictionary-iteration-python3-test.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -From d99c56fa531ba149df84f7a1178ec9a2a740f1ee Mon Sep 17 00:00:00 2001 -From: Corey Bryant -Date: Tue, 9 Jun 2015 13:42:53 -0400 -Subject: [PATCH] Iterate over copy of sys.modules keys in Python2/3 - -Iterate over a copy of sys.modules keys in both Python 2.x and -Python 3.x. In Python 3.x, keys() is not a copy, and therefore -items can't be popped from it while iterating. - -Change-Id: I98c3d7695bbfe3a6a4f23990af45a07dc147f22f -Closes-Bug: #1463503 ---- - keystoneclient/tests/unit/utils.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/keystoneclient/tests/unit/utils.py b/keystoneclient/tests/unit/utils.py -index b3405fb..1b45c36 100644 ---- a/keystoneclient/tests/unit/utils.py -+++ b/keystoneclient/tests/unit/utils.py -@@ -179,7 +179,7 @@ class DisableModuleFixture(fixtures.Fixture): - - def clear_module(self): - cleared_modules = {} -- for fullname in sys.modules.keys(): -+ for fullname in list(sys.modules): - if (fullname == self.module or - fullname.startswith(self.module + '.')): - cleared_modules[fullname] = sys.modules.pop(fullname) --- -2.1.4 - diff -Nru python-keystoneclient-1.6.0/debian/patches/fix-key-iteration.patch python-keystoneclient-1.7.1/debian/patches/fix-key-iteration.patch --- python-keystoneclient-1.6.0/debian/patches/fix-key-iteration.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/fix-key-iteration.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -From bb536dd5d11b88b559f22ff2d5bcd462709ad29a Mon Sep 17 00:00:00 2001 -From: Corey Bryant -Date: Tue, 11 Aug 2015 15:45:59 -0400 -Subject: [PATCH] Iterate over copy of session.adapters keys in Python2/3 -Forwarded: https://review.openstack.org/211731 - -Iterate over a copy of session.adapters keys in both Python 2.x and -Python 3.x. In Python 3.x, keys() is not a copy, and therefore -items can't be popped from it while iterating. - -Change-Id: I4c7ac6e9f69eb409aa991f97ebde6f1581cd27b7 -Closes-Bug: #1483872 ---- - keystoneclient/session.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/keystoneclient/session.py b/keystoneclient/session.py -index cace4f7..113eed7 100644 ---- a/keystoneclient/session.py -+++ b/keystoneclient/session.py -@@ -130,7 +130,7 @@ class Session(object): - if not session: - session = requests.Session() - # Use TCPKeepAliveAdapter to fix bug 1323862 -- for scheme in session.adapters.keys(): -+ for scheme in list(session.adapters): - session.mount(scheme, TCPKeepAliveAdapter()) - - self.auth = auth --- -2.1.4 - diff -Nru python-keystoneclient-1.6.0/debian/patches/fix-test-deprecations.patch python-keystoneclient-1.7.1/debian/patches/fix-test-deprecations.patch --- python-keystoneclient-1.6.0/debian/patches/fix-test-deprecations.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/fix-test-deprecations.patch 2015-10-02 16:08:56.000000000 +0000 @@ -0,0 +1,703 @@ +From 5dea3b22fcc672f3e3405f5abec471929c501c0a Mon Sep 17 00:00:00 2001 +From: Corey Bryant +Date: Fri, 25 Sep 2015 15:42:49 -0400 +Subject: [PATCH] HTTPClient/region_name deprecation test updates +Forwarded: https://review.openstack.org/#/c/228021/ + +Creating an HTTPClient without a session is deprecated and +the ServiceCatalog's region_name parameter is also deprecated. +This follows suite with the following commits to update tests +to handle deprecation warnings: + 803eb235d50daad27074198effc98ca536f1550f + 42bd016e1f0e011ba745dba243e62401298e324c + +Change-Id: I1c5a3dc2c8448873696262ca951c58666c692a61 +Closes-Bug: #1499790 +--- + keystoneclient/tests/unit/v2_0/test_auth.py | 10 +- + keystoneclient/tests/unit/v2_0/test_client.py | 102 ++++++++++-------- + keystoneclient/tests/unit/v2_0/test_discovery.py | 8 +- + .../tests/unit/v2_0/test_service_catalog.py | 4 +- + keystoneclient/tests/unit/v2_0/test_tenants.py | 8 +- + keystoneclient/tests/unit/v2_0/test_tokens.py | 8 +- + keystoneclient/tests/unit/v3/test_auth.py | 114 +++++++++++++-------- + keystoneclient/tests/unit/v3/test_client.py | 104 +++++++++++-------- + keystoneclient/tests/unit/v3/test_discover.py | 4 +- + .../tests/unit/v3/test_service_catalog.py | 6 +- + 10 files changed, 226 insertions(+), 142 deletions(-) + +diff --git a/keystoneclient/tests/unit/v2_0/test_auth.py b/keystoneclient/tests/unit/v2_0/test_auth.py +index c72ecc9..a10fd96 100644 +--- a/keystoneclient/tests/unit/v2_0/test_auth.py ++++ b/keystoneclient/tests/unit/v2_0/test_auth.py +@@ -67,10 +67,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + self.stub_auth(response_list=[{'json': resp_a, 'headers': headers}, + {'json': resp_b, 'headers': headers}]) + +- cs = client.Client(project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL, +- username=self.TEST_USER, +- password=self.TEST_TOKEN) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL, ++ username=self.TEST_USER, ++ password=self.TEST_TOKEN) + + self.assertEqual(cs.management_url, + self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] +diff --git a/keystoneclient/tests/unit/v2_0/test_client.py b/keystoneclient/tests/unit/v2_0/test_client.py +index 447c750..0ef2f6f 100644 +--- a/keystoneclient/tests/unit/v2_0/test_client.py ++++ b/keystoneclient/tests/unit/v2_0/test_client.py +@@ -30,9 +30,11 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.unscoped_token() + self.stub_auth(json=token) + +- c = client.Client(username='exampleuser', +- password='password', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(username='exampleuser', ++ password='password', ++ auth_url=self.TEST_URL) + self.assertIsNotNone(c.auth_ref) + with self.deprecations.expect_deprecations_here(): + self.assertFalse(c.auth_ref.scoped) +@@ -47,10 +49,12 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.project_scoped_token() + self.stub_auth(json=token) + +- c = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + self.assertIsNotNone(c.auth_ref) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(c.auth_ref.scoped) +@@ -65,12 +69,16 @@ class KeystoneClientTest(utils.TestCase): + def test_auth_ref_load(self): + self.stub_auth(json=client_fixtures.project_scoped_token()) + +- cl = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + cache = json.dumps(cl.auth_ref) +- new_client = client.Client(auth_ref=json.loads(cache)) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ new_client = client.Client(auth_ref=json.loads(cache)) + self.assertIsNotNone(new_client.auth_ref) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(new_client.auth_ref.scoped) +@@ -86,14 +94,18 @@ class KeystoneClientTest(utils.TestCase): + def test_auth_ref_load_with_overridden_arguments(self): + self.stub_auth(json=client_fixtures.project_scoped_token()) + +- cl = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + cache = json.dumps(cl.auth_ref) + new_auth_url = "http://new-public:5000/v2.0" +- new_client = client.Client(auth_ref=json.loads(cache), +- auth_url=new_auth_url) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ new_client = client.Client(auth_ref=json.loads(cache), ++ auth_url=new_auth_url) + self.assertIsNotNone(new_client.auth_ref) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(new_client.auth_ref.scoped) +@@ -108,10 +120,12 @@ class KeystoneClientTest(utils.TestCase): + 'http://admin:35357/v2.0') + + def test_init_err_no_auth_url(self): +- self.assertRaises(exceptions.AuthorizationFailure, +- client.Client, +- username='exampleuser', +- password='password') ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ self.assertRaises(exceptions.AuthorizationFailure, ++ client.Client, ++ username='exampleuser', ++ password='password') + + def test_management_url_is_updated(self): + first = fixture.V2Token() +@@ -131,10 +145,12 @@ class KeystoneClientTest(utils.TestCase): + + self.stub_auth(response_list=[{'json': first}, {'json': second}]) + +- cl = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + self.assertEqual(cl.management_url, admin_url) + + cl.authenticate() +@@ -145,27 +161,33 @@ class KeystoneClientTest(utils.TestCase): + # removed ASAP, however must remain compatible. + self.stub_auth(json=client_fixtures.auth_response_body()) + +- cl = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL, +- region_name='North') ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL, ++ region_name='North') + self.assertEqual(cl.service_catalog.url_for(service_type='image'), + 'https://image.north.host/v1/') + +- cl = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL, +- region_name='South') ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL, ++ region_name='South') + self.assertEqual(cl.service_catalog.url_for(service_type='image'), + 'https://image.south.host/v1/') + + def test_client_without_auth_params(self): +- self.assertRaises(exceptions.AuthorizationFailure, +- client.Client, +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ self.assertRaises(exceptions.AuthorizationFailure, ++ client.Client, ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + + def test_client_params(self): + opts = {'auth': token_endpoint.Token('a', 'b'), +diff --git a/keystoneclient/tests/unit/v2_0/test_discovery.py b/keystoneclient/tests/unit/v2_0/test_discovery.py +index 348038a..5afe59a 100644 +--- a/keystoneclient/tests/unit/v2_0/test_discovery.py ++++ b/keystoneclient/tests/unit/v2_0/test_discovery.py +@@ -55,7 +55,9 @@ class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): + self.stub_url('GET', base_url=self.TEST_ROOT_URL, + json=self.TEST_RESPONSE_DICT) + +- cs = client.Client() ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client() + versions = cs.discover(self.TEST_ROOT_URL) + self.assertIsInstance(versions, dict) + self.assertIn('message', versions) +@@ -69,7 +71,9 @@ class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): + self.stub_url('GET', base_url="http://localhost:35357/", + json=self.TEST_RESPONSE_DICT) + +- cs = client.Client() ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client() + versions = cs.discover() + self.assertIsInstance(versions, dict) + self.assertIn('message', versions) +diff --git a/keystoneclient/tests/unit/v2_0/test_service_catalog.py b/keystoneclient/tests/unit/v2_0/test_service_catalog.py +index 1ea3e05..bb2b3ef 100644 +--- a/keystoneclient/tests/unit/v2_0/test_service_catalog.py ++++ b/keystoneclient/tests/unit/v2_0/test_service_catalog.py +@@ -57,7 +57,9 @@ class ServiceCatalogTest(utils.TestCase): + self.assertEqual(url, "https://image.north.host/v1/") + + self.AUTH_RESPONSE_BODY['access']['region_name'] = "South" +- auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) ++ # Setting region_name on the catalog is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) + sc = auth_ref.service_catalog + + url = sc.url_for(service_type='image', endpoint_type='internalURL') +diff --git a/keystoneclient/tests/unit/v2_0/test_tenants.py b/keystoneclient/tests/unit/v2_0/test_tenants.py +index 62ca398..279a8fd 100644 +--- a/keystoneclient/tests/unit/v2_0/test_tenants.py ++++ b/keystoneclient/tests/unit/v2_0/test_tenants.py +@@ -351,9 +351,11 @@ class TenantTests(utils.TestCase): + self.stub_url('GET', ['tenants'], base_url=new_auth_url, + json=self.TEST_TENANTS) + +- c = client.Client(username=self.TEST_USER, +- auth_url=new_auth_url, +- password=uuid.uuid4().hex) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(username=self.TEST_USER, ++ auth_url=new_auth_url, ++ password=uuid.uuid4().hex) + + self.assertIsNone(c.management_url) + tenant_list = c.tenants.list() +diff --git a/keystoneclient/tests/unit/v2_0/test_tokens.py b/keystoneclient/tests/unit/v2_0/test_tokens.py +index d60f0f8..968080b 100644 +--- a/keystoneclient/tests/unit/v2_0/test_tokens.py ++++ b/keystoneclient/tests/unit/v2_0/test_tokens.py +@@ -152,9 +152,11 @@ class TokenTests(utils.TestCase): + token_fixture = fixture.V2Token() + self.stub_auth(base_url=new_auth_url, json=token_fixture) + +- c = client.Client(username=self.TEST_USER, +- auth_url=new_auth_url, +- password=uuid.uuid4().hex) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(username=self.TEST_USER, ++ auth_url=new_auth_url, ++ password=uuid.uuid4().hex) + + self.assertIsNone(c.management_url) + +diff --git a/keystoneclient/tests/unit/v3/test_auth.py b/keystoneclient/tests/unit/v3/test_auth.py +index 8352528..211633b 100644 +--- a/keystoneclient/tests/unit/v3/test_auth.py ++++ b/keystoneclient/tests/unit/v3/test_auth.py +@@ -86,10 +86,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT, subject_token=TEST_TOKEN) + +- cs = client.Client(user_id=self.TEST_USER, +- password=self.TEST_TOKEN, +- project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(user_id=self.TEST_USER, ++ password=self.TEST_TOKEN, ++ project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_token, TEST_TOKEN) + self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) + +@@ -105,11 +107,13 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + # where with assertRaises(exceptions.Unauthorized): doesn't work + # right + def client_create_wrapper(): +- client.Client(user_domain_name=self.TEST_DOMAIN_NAME, +- username=self.TEST_USER, +- password="bad_key", +- project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ client.Client(user_domain_name=self.TEST_DOMAIN_NAME, ++ username=self.TEST_USER, ++ password="bad_key", ++ project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL) + + self.assertRaises(exceptions.Unauthorized, client_create_wrapper) + self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) +@@ -121,11 +125,13 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + self.stub_auth(json=self.TEST_RESPONSE_DICT, + base_url=self.TEST_ADMIN_URL) + +- cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, +- username=self.TEST_USER, +- password=self.TEST_TOKEN, +- project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, ++ username=self.TEST_USER, ++ password=self.TEST_TOKEN, ++ project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL) + + self.assertEqual(cs.management_url, + self.TEST_RESPONSE_DICT["token"]["catalog"][3] +@@ -136,11 +142,13 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + def test_authenticate_success_domain_username_password_scoped(self): + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, +- username=self.TEST_USER, +- password=self.TEST_TOKEN, +- project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, ++ username=self.TEST_USER, ++ password=self.TEST_TOKEN, ++ project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.management_url, + self.TEST_RESPONSE_DICT["token"]["catalog"][3] + ['endpoints'][2]["url"]) +@@ -166,10 +174,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(user_id=self.TEST_USER, +- password=self.TEST_TOKEN, +- domain_id=self.TEST_DOMAIN_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(user_id=self.TEST_USER, ++ password=self.TEST_TOKEN, ++ domain_id=self.TEST_DOMAIN_ID, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_domain_id, + self.TEST_DOMAIN_ID) + self.assertEqual(cs.management_url, +@@ -187,10 +197,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(user_id=self.TEST_USER, +- password=self.TEST_TOKEN, +- project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(user_id=self.TEST_USER, ++ password=self.TEST_TOKEN, ++ project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_tenant_id, + self.TEST_TENANT_ID) + self.assertEqual(cs.management_url, +@@ -206,10 +218,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, +- username=self.TEST_USER, +- password=self.TEST_TOKEN, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(user_domain_name=self.TEST_DOMAIN_NAME, ++ username=self.TEST_USER, ++ password=self.TEST_TOKEN, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_token, + self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) + self.assertFalse('catalog' in cs.service_catalog.catalog) +@@ -224,8 +238,10 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + self.stub_url('GET', [fake_url], json=fake_resp, + base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) + +- cl = client.Client(auth_url=self.TEST_URL, +- token=fake_token) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(auth_url=self.TEST_URL, ++ token=fake_token) + body = jsonutils.loads(self.requests_mock.last_request.body) + self.assertEqual(body['auth']['identity']['token']['id'], fake_token) + +@@ -258,9 +274,11 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(token=self.TEST_TOKEN, +- domain_id=self.TEST_DOMAIN_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(token=self.TEST_TOKEN, ++ domain_id=self.TEST_DOMAIN_ID, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_domain_id, + self.TEST_DOMAIN_ID) + self.assertEqual(cs.management_url, +@@ -280,9 +298,11 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(token=self.TEST_TOKEN, +- project_id=self.TEST_TENANT_ID, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(token=self.TEST_TOKEN, ++ project_id=self.TEST_TENANT_ID, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_tenant_id, + self.TEST_TENANT_ID) + self.assertEqual(cs.management_url, +@@ -304,8 +324,10 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + + self.stub_auth(json=self.TEST_RESPONSE_DICT) + +- cs = client.Client(token=self.TEST_TOKEN, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client(token=self.TEST_TOKEN, ++ auth_url=self.TEST_URL) + self.assertEqual(cs.auth_token, + self.TEST_RESPONSE_HEADERS["X-Subject-Token"]) + self.assertFalse('catalog' in cs.service_catalog.catalog) +@@ -320,10 +342,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase): + self.stub_url('GET', [fake_url], json=fake_resp, + base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) + +- cl = client.Client(username='exampleuser', +- password='password', +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + + self.assertEqual(cl.auth_token, self.TEST_TOKEN) + +diff --git a/keystoneclient/tests/unit/v3/test_client.py b/keystoneclient/tests/unit/v3/test_client.py +index 82e0798..e35810e 100644 +--- a/keystoneclient/tests/unit/v3/test_client.py ++++ b/keystoneclient/tests/unit/v3/test_client.py +@@ -30,10 +30,12 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.unscoped_token() + self.stub_auth(json=token) + +- c = client.Client(user_domain_name=token.user_domain_name, +- username=token.user_name, +- password='password', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(user_domain_name=token.user_domain_name, ++ username=token.user_name, ++ password='password', ++ auth_url=self.TEST_URL) + self.assertIsNotNone(c.auth_ref) + self.assertFalse(c.auth_ref.domain_scoped) + self.assertFalse(c.auth_ref.project_scoped) +@@ -47,10 +49,12 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.domain_scoped_token() + self.stub_auth(json=token) + +- c = client.Client(user_id=token.user_id, +- password='password', +- domain_name=token.domain_name, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(user_id=token.user_id, ++ password='password', ++ domain_name=token.domain_name, ++ auth_url=self.TEST_URL) + self.assertIsNotNone(c.auth_ref) + self.assertTrue(c.auth_ref.domain_scoped) + self.assertFalse(c.auth_ref.project_scoped) +@@ -61,11 +65,13 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.project_scoped_token() + self.stub_auth(json=token), + +- c = client.Client(user_id=token.user_id, +- password='password', +- user_domain_name=token.user_domain_name, +- project_name=token.project_name, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(user_id=token.user_id, ++ password='password', ++ user_domain_name=token.user_domain_name, ++ project_name=token.project_name, ++ auth_url=self.TEST_URL) + self.assertIsNotNone(c.auth_ref) + self.assertFalse(c.auth_ref.domain_scoped) + self.assertTrue(c.auth_ref.project_scoped) +@@ -78,12 +84,16 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.project_scoped_token() + self.stub_auth(json=token) + +- c = client.Client(user_id=token.user_id, +- password='password', +- project_id=token.project_id, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(user_id=token.user_id, ++ password='password', ++ project_id=token.project_id, ++ auth_url=self.TEST_URL) + cache = json.dumps(c.auth_ref) +- new_client = client.Client(auth_ref=json.loads(cache)) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ new_client = client.Client(auth_ref=json.loads(cache)) + self.assertIsNotNone(new_client.auth_ref) + self.assertFalse(new_client.auth_ref.domain_scoped) + self.assertTrue(new_client.auth_ref.project_scoped) +@@ -108,13 +118,17 @@ class KeystoneClientTest(utils.TestCase): + self.stub_auth(json=first) + self.stub_auth(json=second, base_url=new_auth_url) + +- c = client.Client(user_id=user_id, +- password='password', +- project_id=project_id, +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(user_id=user_id, ++ password='password', ++ project_id=project_id, ++ auth_url=self.TEST_URL) + cache = json.dumps(c.auth_ref) +- new_client = client.Client(auth_ref=json.loads(cache), +- auth_url=new_auth_url) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ new_client = client.Client(auth_ref=json.loads(cache), ++ auth_url=new_auth_url) + self.assertIsNotNone(new_client.auth_ref) + self.assertFalse(new_client.auth_ref.domain_scoped) + self.assertTrue(new_client.auth_ref.project_scoped) +@@ -128,11 +142,13 @@ class KeystoneClientTest(utils.TestCase): + token = client_fixtures.trust_token() + self.stub_auth(json=token) + +- c = client.Client(user_domain_name=token.user_domain_name, +- username=token.user_name, +- password='password', +- auth_url=self.TEST_URL, +- trust_id=token.trust_id) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ c = client.Client(user_domain_name=token.user_domain_name, ++ username=token.user_name, ++ password='password', ++ auth_url=self.TEST_URL, ++ trust_id=token.trust_id) + self.assertIsNotNone(c.auth_ref) + self.assertFalse(c.auth_ref.domain_scoped) + self.assertFalse(c.auth_ref.project_scoped) +@@ -143,10 +159,12 @@ class KeystoneClientTest(utils.TestCase): + self.assertEqual(token.user_id, c.auth_user_id) + + def test_init_err_no_auth_url(self): +- self.assertRaises(exceptions.AuthorizationFailure, +- client.Client, +- username='exampleuser', +- password='password') ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ self.assertRaises(exceptions.AuthorizationFailure, ++ client.Client, ++ username='exampleuser', ++ password='password') + + def _management_url_is_updated(self, fixture, **kwargs): + second = copy.deepcopy(fixture) +@@ -171,10 +189,12 @@ class KeystoneClientTest(utils.TestCase): + + self.stub_auth(response_list=[{'json': fixture}, {'json': second}]) + +- cl = client.Client(username='exampleuser', +- password='password', +- auth_url=self.TEST_URL, +- **kwargs) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cl = client.Client(username='exampleuser', ++ password='password', ++ auth_url=self.TEST_URL, ++ **kwargs) + self.assertEqual(cl.management_url, first_url) + + cl.authenticate() +@@ -212,10 +232,12 @@ class KeystoneClientTest(utils.TestCase): + 'http://glance.south.host/glanceapi/public') + + def test_client_without_auth_params(self): +- self.assertRaises(exceptions.AuthorizationFailure, +- client.Client, +- project_name='exampleproject', +- auth_url=self.TEST_URL) ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ self.assertRaises(exceptions.AuthorizationFailure, ++ client.Client, ++ project_name='exampleproject', ++ auth_url=self.TEST_URL) + + def test_client_params(self): + opts = {'auth': token_endpoint.Token('a', 'b'), +diff --git a/keystoneclient/tests/unit/v3/test_discover.py b/keystoneclient/tests/unit/v3/test_discover.py +index ae88bb4..898d46b 100644 +--- a/keystoneclient/tests/unit/v3/test_discover.py ++++ b/keystoneclient/tests/unit/v3/test_discover.py +@@ -65,7 +65,9 @@ class DiscoverKeystoneTests(utils.UnauthenticatedTestCase): + status_code=300, + json=self.TEST_RESPONSE_DICT) + +- cs = client.Client() ++ # Creating a HTTPClient not using session is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ cs = client.Client() + versions = cs.discover() + self.assertIsInstance(versions, dict) + self.assertIn('message', versions) +diff --git a/keystoneclient/tests/unit/v3/test_service_catalog.py b/keystoneclient/tests/unit/v3/test_service_catalog.py +index f1bb08f..0e7d55c 100644 +--- a/keystoneclient/tests/unit/v3/test_service_catalog.py ++++ b/keystoneclient/tests/unit/v3/test_service_catalog.py +@@ -76,8 +76,10 @@ class ServiceCatalogTest(utils.TestCase): + self.assertEqual(url, "http://glance.north.host/glanceapi/public") + + self.AUTH_RESPONSE_BODY['token']['region_name'] = "South" +- auth_ref = access.AccessInfo.factory(self.RESPONSE, +- self.AUTH_RESPONSE_BODY) ++ # Setting region_name on the catalog is deprecated. ++ with self.deprecations.expect_deprecations_here(): ++ auth_ref = access.AccessInfo.factory(self.RESPONSE, ++ self.AUTH_RESPONSE_BODY) + sc = auth_ref.service_catalog + url = sc.url_for(service_type='image', endpoint_type='internal') + self.assertEqual(url, "http://glance.south.host/glanceapi/internal") +-- +2.5.0 + diff -Nru python-keystoneclient-1.6.0/debian/patches/oauth-use-actual-request-headers.patch python-keystoneclient-1.7.1/debian/patches/oauth-use-actual-request-headers.patch --- python-keystoneclient-1.6.0/debian/patches/oauth-use-actual-request-headers.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/oauth-use-actual-request-headers.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -From 7d5d8b343232ee5faf4de3381024095619335929 Mon Sep 17 00:00:00 2001 -From: Boris Bobrov -Date: Wed, 22 Jul 2015 18:52:49 +0300 -Subject: [PATCH] Make OAuth testcase use actual request headers - -OAuth test verifies that access_token manager's methods make requests with -certain parameters. It is supposed to use values from mocked http handler -and compare them with referential values acquired from oauth client. - -But instead of using values from mocked handler, it used the values from -oauth client and compared them with values from the client acquired using -attributes, basically testing oauthlib and not access_token manager's -methods. - -Make the test compare correct values and remove check of timestamp, -which was useless because it is always mocked in tests and not provided in -actual requests. - -As a consequence, use of get_oauth_params, which changed in oauthlib -1.0 and blocked the gate, was removed. - -Closes-Bug: 1477177 -Closes-Bug: 1477247 -Change-Id: I5e049163f84fde5827104fd4a6441222eb08468f ---- - keystoneclient/tests/unit/v3/test_oauth1.py | 20 ++++---------------- - 1 file changed, 4 insertions(+), 16 deletions(-) - -diff --git a/keystoneclient/tests/unit/v3/test_oauth1.py b/keystoneclient/tests/unit/v3/test_oauth1.py -index 48af836..2ebfa50 100644 ---- a/keystoneclient/tests/unit/v3/test_oauth1.py -+++ b/keystoneclient/tests/unit/v3/test_oauth1.py -@@ -28,7 +28,6 @@ from keystoneclient.v3.contrib.oauth1 import consumers - from keystoneclient.v3.contrib.oauth1 import request_tokens - - try: -- import oauthlib - from oauthlib import oauth1 - except ImportError: - oauth1 = None -@@ -103,16 +102,8 @@ class TokenTests(BaseTest): - """ - - self.assertThat(auth_header, matchers.StartsWith('OAuth ')) -- auth_header = auth_header[len('OAuth '):] -- # NOTE(stevemar): In newer versions of oauthlib there is -- # an additional argument for getting oauth parameters. -- # Adding a conditional here to revert back to no arguments -- # if an earlier version is detected. -- if tuple(oauthlib.__version__.split('.')) > ('0', '6', '1'): -- header_params = oauth_client.get_oauth_params(None) -- else: -- header_params = oauth_client.get_oauth_params() -- parameters = dict(header_params) -+ parameters = dict( -+ oauth1.rfc5849.utils.parse_authorization_header(auth_header)) - - self.assertEqual('HMAC-SHA1', parameters['oauth_signature_method']) - self.assertEqual('1.0', parameters['oauth_version']) -@@ -128,9 +119,6 @@ class TokenTests(BaseTest): - if oauth_client.callback_uri: - self.assertEqual(oauth_client.callback_uri, - parameters['oauth_callback']) -- if oauth_client.timestamp: -- self.assertEqual(oauth_client.timestamp, -- parameters['oauth_timestamp']) - return parameters - - -@@ -229,8 +217,8 @@ class AccessTokenTests(TokenTests): - resource_owner_key=request_key, - resource_owner_secret=request_secret, - signature_method=oauth1.SIGNATURE_HMAC, -- verifier=verifier, -- timestamp=expires_at) -+ verifier=verifier) -+ - self._validate_oauth_headers(req_headers['Authorization'], - oauth_client) - --- -2.1.4 - diff -Nru python-keystoneclient-1.6.0/debian/patches/series python-keystoneclient-1.7.1/debian/patches/series --- python-keystoneclient-1.6.0/debian/patches/series 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/series 2015-10-02 16:08:56.000000000 +0000 @@ -1,7 +1,4 @@ -fix-dictionary-iteration-python3-test.patch skip-pep8-python3-test.patch -fix-assertRaisesRegex-python3-tests.patch skip-memcache-python3-test.patch -fix-key-iteration.patch +#fix-key-iteration.patch fix-1368545.patch -oauth-use-actual-request-headers.patch diff -Nru python-keystoneclient-1.6.0/debian/patches/skip-memcache-python3-test.patch python-keystoneclient-1.7.1/debian/patches/skip-memcache-python3-test.patch --- python-keystoneclient-1.6.0/debian/patches/skip-memcache-python3-test.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/skip-memcache-python3-test.patch 2015-10-02 16:08:56.000000000 +0000 @@ -5,9 +5,11 @@ Forwarded: No Last-Update: 2015-06-12 ---- a/keystoneclient/tests/unit/test_auth_token_middleware.py -+++ b/keystoneclient/tests/unit/test_auth_token_middleware.py -@@ -21,6 +21,7 @@ +Index: python-keystoneclient/keystoneclient/tests/unit/test_auth_token_middleware.py +=================================================================== +--- python-keystoneclient.orig/keystoneclient/tests/unit/test_auth_token_middleware.py ++++ python-keystoneclient/keystoneclient/tests/unit/test_auth_token_middleware.py +@@ -21,6 +21,7 @@ import stat import tempfile import time import uuid @@ -15,7 +17,7 @@ import fixtures import iso8601 -@@ -89,13 +90,22 @@ +@@ -90,13 +91,22 @@ def memcached_available(): global MEMCACHED_AVAILABLE if MEMCACHED_AVAILABLE is None: diff -Nru python-keystoneclient-1.6.0/debian/patches/skip-pep8-python3-test.patch python-keystoneclient-1.7.1/debian/patches/skip-pep8-python3-test.patch --- python-keystoneclient-1.6.0/debian/patches/skip-pep8-python3-test.patch 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/patches/skip-pep8-python3-test.patch 2015-10-02 16:08:56.000000000 +0000 @@ -4,9 +4,11 @@ Forwarded: No Last-Update: 2015-06-09 ---- a/keystoneclient/tests/unit/test_hacking_checks.py -+++ b/keystoneclient/tests/unit/test_hacking_checks.py -@@ -44,4 +44,7 @@ +Index: python-keystoneclient/keystoneclient/tests/unit/test_hacking_checks.py +=================================================================== +--- python-keystoneclient.orig/keystoneclient/tests/unit/test_hacking_checks.py ++++ python-keystoneclient/keystoneclient/tests/unit/test_hacking_checks.py +@@ -47,4 +47,7 @@ class TestCheckOsloNamespaceImports(test code_ex = self.useFixture(client_fixtures.HackingCode()) code = code_ex.oslo_namespace_imports['code'] errors = code_ex.oslo_namespace_imports['expected_errors'] diff -Nru python-keystoneclient-1.6.0/debian/rules python-keystoneclient-1.7.1/debian/rules --- python-keystoneclient-1.6.0/debian/rules 2015-09-05 13:36:25.000000000 +0000 +++ python-keystoneclient-1.7.1/debian/rules 2015-10-02 16:08:56.000000000 +0000 @@ -29,7 +29,7 @@ override_dh_auto_test: ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - set -e ; for i in 2.7 3.4 ; do \ + set -e ; for i in 2.7 ; do \ PYMAJOR=`echo $$i | cut -d'.' -f1` ; \ echo "===> Testing with python$$i (python$$PYMAJOR)" ; \ rm -rf .testrepository ; \ diff -Nru python-keystoneclient-1.6.0/doc/source/conf.py python-keystoneclient-1.7.1/doc/source/conf.py --- python-keystoneclient-1.6.0/doc/source/conf.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/doc/source/conf.py 2015-09-09 04:34:24.000000000 +0000 @@ -103,7 +103,7 @@ pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +modindex_common_prefix = ['keystoneclient.'] # Grouping the document tree for man pages. # List of tuples 'sourcefile', 'target', 'title', 'Authors name', 'manual' diff -Nru python-keystoneclient-1.6.0/doc/source/images/graphs_authCompDelegate.svg python-keystoneclient-1.7.1/doc/source/images/graphs_authCompDelegate.svg --- python-keystoneclient-1.6.0/doc/source/images/graphs_authCompDelegate.svg 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/doc/source/images/graphs_authCompDelegate.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ - - - - - - -AuthCompDelegate - - -AuthComp - -Auth -Component - - - -AuthComp->Reject - - -Reject Requests -Indicated by the Service - - -Service - -OpenStack -Service - - -AuthComp->Service - - -Forward Requests -with Identiy Status - - -Service->AuthComp - - -Send Response OR -Reject Message - - - -Start->AuthComp - - - - - diff -Nru python-keystoneclient-1.6.0/doc/source/images/graphs_authComp.svg python-keystoneclient-1.7.1/doc/source/images/graphs_authComp.svg --- python-keystoneclient-1.6.0/doc/source/images/graphs_authComp.svg 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/doc/source/images/graphs_authComp.svg 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ - - - - - - -AuthComp - - -AuthComp - -Auth -Component - - - -AuthComp->Reject - - -Reject -Unauthenticated -Requests - - -Service - -OpenStack -Service - - -AuthComp->Service - - -Forward -Authenticated -Requests - - - -Start->AuthComp - - - - - diff -Nru python-keystoneclient-1.6.0/keystoneclient/access.py python-keystoneclient-1.7.1/keystoneclient/access.py --- python-keystoneclient-1.6.0/keystoneclient/access.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/access.py 2015-09-09 04:34:24.000000000 +0000 @@ -16,6 +16,7 @@ import datetime +import warnings from oslo_utils import timeutils @@ -39,9 +40,20 @@ **kwargs): """Create AccessInfo object given a successful auth response & body or a user-provided dict. + + .. warning:: + + Use of the region_name argument is deprecated as of the 1.7.0 + release and may be removed in the 2.0.0 release. + """ - # FIXME(jamielennox): Passing region_name is deprecated. Provide an - # appropriate warning. + + if region_name: + warnings.warn( + 'Use of the region_name argument is deprecated as of the ' + '1.7.0 release and may be removed in the 2.0.0 release.', + DeprecationWarning) + auth_ref = None if body is not None or len(kwargs): @@ -246,7 +258,10 @@ """Returns true if the authorization token was scoped to a tenant (project), and contains a populated service catalog. - This is deprecated, use project_scoped instead. + .. warning:: + + This is deprecated as of the 1.7.0 release in favor of + project_scoped and may be removed in the 2.0.0 release. :returns: bool """ @@ -349,7 +364,8 @@ (project), this property will return None. DEPRECATED: this doesn't correctly handle region name. You should fetch - it from the service catalog yourself. + it from the service catalog yourself. This may be removed in the 2.0.0 + release. :returns: tuple of urls """ @@ -362,7 +378,8 @@ authentication request wasn't scoped to a tenant (project). DEPRECATED: this doesn't correctly handle region name. You should fetch - it from the service catalog yourself. + it from the service catalog yourself. This may be removed in the 2.0.0 + release. :returns: tuple of urls """ @@ -525,6 +542,13 @@ @property def scoped(self): + """Deprecated as of the 1.7.0 release in favor of project_scoped and + may be removed in the 2.0.0 release. + """ + warnings.warn( + 'scoped is deprecated as of the 1.7.0 release in favor of ' + 'project_scoped and may be removed in the 2.0.0 release.', + DeprecationWarning) if ('serviceCatalog' in self and self['serviceCatalog'] and 'tenant' in self['token']): @@ -589,8 +613,13 @@ @property def auth_url(self): - # FIXME(jamielennox): this is deprecated in favour of retrieving it - # from the service catalog. Provide a warning. + """Deprecated as of the 1.7.0 release in favor of + service_catalog.get_urls() and may be removed in the 2.0.0 release. + """ + warnings.warn( + 'auth_url is deprecated as of the 1.7.0 release in favor of ' + 'service_catalog.get_urls() and may be removed in the 2.0.0 ' + 'release.', DeprecationWarning) if self.service_catalog: return self.service_catalog.get_urls(service_type='identity', endpoint_type='publicURL', @@ -600,8 +629,13 @@ @property def management_url(self): - # FIXME(jamielennox): this is deprecated in favour of retrieving it - # from the service catalog. Provide a warning. + """Deprecated as of the 1.7.0 release in favor of + service_catalog.get_urls() and may be removed in the 2.0.0 release. + """ + warnings.warn( + 'management_url is deprecated as of the 1.7.0 release in favor of ' + 'service_catalog.get_urls() and may be removed in the 2.0.0 ' + 'release.', DeprecationWarning) if self.service_catalog: return self.service_catalog.get_urls(service_type='identity', endpoint_type='adminURL', @@ -747,6 +781,13 @@ @property def scoped(self): + """Deprecated as of the 1.7.0 release in favor of project_scoped and + may be removed in the 2.0.0 release. + """ + warnings.warn( + 'scoped is deprecated as of the 1.7.0 release in favor of ' + 'project_scoped and may be removed in the 2.0.0 release.', + DeprecationWarning) return ('catalog' in self and self['catalog'] and 'project' in self) @property @@ -775,8 +816,13 @@ @property def auth_url(self): - # FIXME(jamielennox): this is deprecated in favour of retrieving it - # from the service catalog. Provide a warning. + """Deprecated as of the 1.7.0 release in favor of + service_catalog.get_urls() and may be removed in the 2.0.0 release. + """ + warnings.warn( + 'auth_url is deprecated as of the 1.7.0 release in favor of ' + 'service_catalog.get_urls() and may be removed in the 2.0.0 ' + 'release.', DeprecationWarning) if self.service_catalog: return self.service_catalog.get_urls(service_type='identity', endpoint_type='public', @@ -786,8 +832,13 @@ @property def management_url(self): - # FIXME(jamielennox): this is deprecated in favour of retrieving it - # from the service catalog. Provide a warning. + """Deprecated as of the 1.7.0 release in favor of + service_catalog.get_urls() and may be removed in the 2.0.0 release. + """ + warnings.warn( + 'management_url is deprecated as of the 1.7.0 release in favor of ' + 'service_catalog.get_urls() and may be removed in the 2.0.0 ' + 'release.', DeprecationWarning) if self.service_catalog: return self.service_catalog.get_urls(service_type='identity', endpoint_type='admin', diff -Nru python-keystoneclient-1.6.0/keystoneclient/apiclient/exceptions.py python-keystoneclient-1.7.1/keystoneclient/apiclient/exceptions.py --- python-keystoneclient-1.6.0/keystoneclient/apiclient/exceptions.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/apiclient/exceptions.py 2015-09-09 04:34:24.000000000 +0000 @@ -20,14 +20,15 @@ Exception definitions. Deprecated since v0.7.1. Use 'keystoneclient.exceptions' instead of -this module. +this module. This module may be removed in the 2.0.0 release. """ -import warnings +from debtcollector import removals from keystoneclient.exceptions import * # noqa -warnings.warn("The 'keystoneclient.apiclient.exceptions' module is deprecated " - "since v.0.7.1. Use 'keystoneclient.exceptions' instead of this " - "module.", DeprecationWarning) +removals.removed_module('keystoneclient.apiclient.exceptions', + replacement='keystoneclient.exceptions', + version='0.7.1', + removal_version='2.0') diff -Nru python-keystoneclient-1.6.0/keystoneclient/apiclient/__init__.py python-keystoneclient-1.7.1/keystoneclient/apiclient/__init__.py --- python-keystoneclient-1.6.0/keystoneclient/apiclient/__init__.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/apiclient/__init__.py 2015-09-09 04:34:24.000000000 +0000 @@ -13,7 +13,16 @@ # License for the specific language governing permissions and limitations # under the License. -import warnings +"""Deprecated. + +.. warning:: + + This module is deprecated as of the 1.7.0 release in favor of + :py:mod:`keystoneclient.exceptions` and may be removed in the 2.0.0 release. + +""" + +from debtcollector import removals from keystoneclient import exceptions @@ -22,9 +31,10 @@ # to report 'deprecated' status of exceptions for next kind of imports # from keystoneclient.apiclient import exceptions -warnings.warn("The 'keystoneclient.apiclient' module is deprecated since " - "v.0.7.1. Use 'keystoneclient.exceptions' instead of this " - "module.", DeprecationWarning) +removals.removed_module('keystoneclient.apiclient', + replacement='keystoneclient.exceptions', + version='0.7.1', + removal_version='2.0') __all__ = [ 'exceptions', diff -Nru python-keystoneclient-1.6.0/keystoneclient/auth/base.py python-keystoneclient-1.7.1/keystoneclient/auth/base.py --- python-keystoneclient-1.6.0/keystoneclient/auth/base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/auth/base.py 2015-09-09 04:34:24.000000000 +0000 @@ -168,6 +168,19 @@ """ return None + def get_connection_params(self, session, **kwargs): + """Return any additional connection parameters required for the plugin. + + :param session: The session object that the auth_plugin belongs to. + :type session: keystoneclient.session.Session + + :returns: Headers that are set to authenticate a message or None for + failure. Note that when checking this value that the empty + dict is a valid, non-failure response. + :rtype: dict + """ + return {} + def invalidate(self): """Invalidate the current authentication data. diff -Nru python-keystoneclient-1.6.0/keystoneclient/auth/identity/base.py python-keystoneclient-1.7.1/keystoneclient/auth/identity/base.py --- python-keystoneclient-1.6.0/keystoneclient/auth/identity/base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/auth/identity/base.py 2015-09-09 04:34:24.000000000 +0000 @@ -12,6 +12,7 @@ import abc import logging +import warnings from oslo_config import cfg import six @@ -54,12 +55,106 @@ self._endpoint_cache = {} - # NOTE(jamielennox): DEPRECATED. The following should not really be set - # here but handled by the individual auth plugin. - self.username = username - self.password = password - self.token = token - self.trust_id = trust_id + self._username = username + self._password = password + self._token = token + self._trust_id = trust_id + + @property + def username(self): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'username is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + return self._username + + @username.setter + def username(self, value): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'username is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + self._username = value + + @property + def password(self): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'password is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + return self._password + + @password.setter + def password(self, value): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'password is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + self._password = value + + @property + def token(self): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'token is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + return self._token + + @token.setter + def token(self, value): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'token is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + self._token = value + + @property + def trust_id(self): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'trust_id is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + return self._trust_id + + @trust_id.setter + def trust_id(self, value): + """Deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + """ + + warnings.warn( + 'trust_id is deprecated as of the 1.7.0 release and may be ' + 'removed in the 2.0.0 release.', DeprecationWarning) + + self._trust_id = value @abc.abstractmethod def get_auth_ref(self, session, **kwargs): @@ -208,9 +303,10 @@ else: if not service_type: - LOG.warn(_LW('Plugin cannot return an endpoint without ' - 'knowing the service type that is required. Add ' - 'service_type to endpoint filtering data.')) + LOG.warning(_LW( + 'Plugin cannot return an endpoint without knowing the ' + 'service type that is required. Add service_type to ' + 'endpoint filtering data.')) return None if not interface: @@ -243,9 +339,10 @@ # NOTE(jamielennox): Again if we can't contact the server we fall # back to just returning the URL from the catalog. This may not be # the best default but we need it for now. - LOG.warn(_LW('Failed to contact the endpoint at %s for discovery. ' - 'Fallback to using that endpoint as the base url.'), - url) + LOG.warning(_LW( + 'Failed to contact the endpoint at %s for discovery. Fallback ' + 'to using that endpoint as the base url.'), + url) else: url = disc.url_for(version) diff -Nru python-keystoneclient-1.6.0/keystoneclient/auth/identity/generic/base.py python-keystoneclient-1.7.1/keystoneclient/auth/identity/generic/base.py --- python-keystoneclient-1.6.0/keystoneclient/auth/identity/generic/base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/auth/identity/generic/base.py 2015-09-09 04:34:24.000000000 +0000 @@ -72,6 +72,16 @@ self._plugin = None + @property + def trust_id(self): + # Override to remove deprecation. + return self._trust_id + + @trust_id.setter + def trust_id(self, value): + # Override to remove deprecation. + self._trust_id = value + @abc.abstractmethod def create_plugin(self, session, version, url, raw_status=None): """Create a plugin from the given paramters. @@ -130,9 +140,9 @@ except (exceptions.DiscoveryFailure, exceptions.HTTPError, exceptions.ConnectionError): - LOG.warn(_LW('Discovering versions from the identity service ' - 'failed when creating the password plugin. ' - 'Attempting to determine version from URL.')) + LOG.warning(_LW('Discovering versions from the identity service ' + 'failed when creating the password plugin. ' + 'Attempting to determine version from URL.')) url_parts = urlparse.urlparse(self.auth_url) path = url_parts.path.lower() diff -Nru python-keystoneclient-1.6.0/keystoneclient/auth/identity/v2.py python-keystoneclient-1.7.1/keystoneclient/auth/identity/v2.py --- python-keystoneclient-1.6.0/keystoneclient/auth/identity/v2.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/auth/identity/v2.py 2015-09-09 04:34:24.000000000 +0000 @@ -57,10 +57,20 @@ super(Auth, self).__init__(auth_url=auth_url, reauthenticate=reauthenticate) - self.trust_id = trust_id + self._trust_id = trust_id self.tenant_id = tenant_id self.tenant_name = tenant_name + @property + def trust_id(self): + # Override to remove deprecation. + return self._trust_id + + @trust_id.setter + def trust_id(self, value): + # Override to remove deprecation. + self._trust_id = value + def get_auth_ref(self, session, **kwargs): headers = {'Accept': 'application/json'} url = self.auth_url.rstrip('/') + '/tokens' @@ -131,8 +141,28 @@ user_id = None self.user_id = user_id - self.username = username - self.password = password + self._username = username + self._password = password + + @property + def username(self): + # Override to remove deprecation. + return self._username + + @username.setter + def username(self, value): + # Override to remove deprecation. + self._username = value + + @property + def password(self): + # Override to remove deprecation. + return self._password + + @password.setter + def password(self, value): + # Override to remove deprecation. + self._password = value def get_auth_data(self, headers=None): auth = {'password': self.password} @@ -182,7 +212,17 @@ def __init__(self, auth_url, token, **kwargs): super(Token, self).__init__(auth_url, **kwargs) - self.token = token + self._token = token + + @property + def token(self): + # Override to remove deprecation. + return self._token + + @token.setter + def token(self, value): + # Override to remove deprecation. + self._token = value def get_auth_data(self, headers=None): if headers is not None: diff -Nru python-keystoneclient-1.6.0/keystoneclient/auth/identity/v3/base.py python-keystoneclient-1.7.1/keystoneclient/auth/identity/v3/base.py --- python-keystoneclient-1.6.0/keystoneclient/auth/identity/v3/base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/auth/identity/v3/base.py 2015-09-09 04:34:24.000000000 +0000 @@ -59,7 +59,7 @@ include_catalog=True): super(BaseAuth, self).__init__(auth_url=auth_url, reauthenticate=reauthenticate) - self.trust_id = trust_id + self._trust_id = trust_id self.domain_id = domain_id self.domain_name = domain_name self.project_id = project_id @@ -69,6 +69,16 @@ self.include_catalog = include_catalog @property + def trust_id(self): + # Override to remove deprecation. + return self._trust_id + + @trust_id.setter + def trust_id(self, value): + # Override to remove deprecation. + self._trust_id = value + + @property def token_url(self): """The full URL where we will send authentication data.""" return '%s/auth/tokens' % self.auth_url.rstrip('/') @@ -208,7 +218,7 @@ setattr(self, param, kwargs.pop(param, None)) if kwargs: - msg = _("Unexpected Attributes: %s") % ", ".join(kwargs.keys()) + msg = _("Unexpected Attributes: %s") % ", ".join(kwargs) raise AttributeError(msg) @classmethod diff -Nru python-keystoneclient-1.6.0/keystoneclient/base.py python-keystoneclient-1.7.1/keystoneclient/base.py --- python-keystoneclient-1.6.0/keystoneclient/base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/base.py 2015-09-09 04:34:24.000000000 +0000 @@ -20,15 +20,17 @@ """ import abc +import copy import functools +import warnings +from oslo_utils import strutils import six from six.moves import urllib from keystoneclient import auth from keystoneclient import exceptions from keystoneclient.i18n import _ -from keystoneclient.openstack.common.apiclient import base def getid(obj): @@ -91,8 +93,17 @@ @property def api(self): - """Deprecated. Use `client` instead. + """The client. + + .. warning:: + + This property is deprecated as of the 1.7.0 release in favor of + :meth:`client` and may be removed in the 2.0.0 release. + """ + warnings.warn( + 'api is deprecated as of the 1.7.0 release in favor of client and ' + 'may be removed in the 2.0.0 release', DeprecationWarning) return self.client def _list(self, url, response_key, obj_class=None, body=None, **kwargs): @@ -356,6 +367,17 @@ @filter_kwargs def list(self, fallback_to_auth=False, **kwargs): + if 'id' in kwargs.keys(): + # Ensure that users are not trying to call things like + # ``domains.list(id='default')`` when they should have used + # ``[domains.get(domain_id='default')]`` instead. Keystone supports + # ``GET /v3/domains/{domain_id}``, not ``GET + # /v3/domains?id={domain_id}``. + raise TypeError( + _("list() got an unexpected keyword argument 'id'. To " + "retrieve a single object using a globally unique " + "identifier, try using get() instead.")) + url = self.build_url(dict_args_in_out=kwargs) try: @@ -418,11 +440,99 @@ return rl[0] -class Resource(base.Resource): +class Resource(object): """Base class for OpenStack resources (tenant, user, etc.). This is pretty much just a bag for attributes. """ + HUMAN_ID = False + NAME_ATTR = 'name' + + def __init__(self, manager, info, loaded=False): + """Populate and bind to a manager. + + :param manager: BaseManager object + :param info: dictionary representing resource attributes + :param loaded: prevent lazy-loading if set to True + """ + self.manager = manager + self._info = info + self._add_details(info) + self._loaded = loaded + + def __repr__(self): + reprkeys = sorted(k + for k in self.__dict__.keys() + if k[0] != '_' and k != 'manager') + info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) + return "<%s %s>" % (self.__class__.__name__, info) + + @property + def human_id(self): + """Human-readable ID which can be used for bash completion. + """ + if self.HUMAN_ID: + name = getattr(self, self.NAME_ATTR, None) + if name is not None: + return strutils.to_slug(name) + return None + + def _add_details(self, info): + for (k, v) in six.iteritems(info): + try: + setattr(self, k, v) + self._info[k] = v + except AttributeError: + # In this case we already defined the attribute on the class + pass + + def __getattr__(self, k): + if k not in self.__dict__: + # NOTE(bcwaldon): disallow lazy-loading if already loaded once + if not self.is_loaded(): + self.get() + return self.__getattr__(k) + + raise AttributeError(k) + else: + return self.__dict__[k] + + def get(self): + """Support for lazy loading details. + + Some clients, such as novaclient have the option to lazy load the + details, details which can be loaded with this function. + """ + # set_loaded() first ... so if we have to bail, we know we tried. + self.set_loaded(True) + if not hasattr(self.manager, 'get'): + return + + new = self.manager.get(self.id) + if new: + self._add_details(new._info) + self._add_details( + {'x_request_id': self.manager.client.last_request_id}) + + def __eq__(self, other): + if not isinstance(other, Resource): + return NotImplemented + # two resources of different types are not equal + if not isinstance(other, self.__class__): + return False + if hasattr(self, 'id') and hasattr(other, 'id'): + return self.id == other.id + return self._info == other._info + + def is_loaded(self): + return self._loaded + + def set_loaded(self, val): + self._loaded = val + + def to_dict(self): + return copy.deepcopy(self._info) + def delete(self): return self.manager.delete(self) diff -Nru python-keystoneclient-1.6.0/keystoneclient/client.py python-keystoneclient-1.7.1/keystoneclient/client.py --- python-keystoneclient-1.6.0/keystoneclient/client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/client.py 2015-09-09 04:34:24.000000000 +0000 @@ -10,13 +10,23 @@ # License for the specific language governing permissions and limitations # under the License. +from debtcollector import removals + from keystoneclient import discover from keystoneclient import httpclient from keystoneclient import session as client_session -# Using client.HTTPClient is deprecated. Use httpclient.HTTPClient instead. -HTTPClient = httpclient.HTTPClient +@removals.remove(message='Use keystoneclient.httpclient.HTTPClient instead', + version='1.7.0', removal_version='2.0.0') +class HTTPClient(httpclient.HTTPClient): + """Deprecated alias for httpclient.HTTPClient. + + This class is deprecated as of the 1.7.0 release in favor of + :class:`keystoneclient.httpclient.HTTPClient` and may be removed in the + 2.0.0 release. + + """ def Client(version=None, unstable=False, session=None, **kwargs): @@ -47,7 +57,7 @@ cannot be found. """ if not session: - session = client_session.Session.construct(kwargs) + session = client_session.Session._construct(kwargs) d = discover.Discover(session=session, **kwargs) return d.create_client(version=version, unstable=unstable) diff -Nru python-keystoneclient-1.6.0/keystoneclient/common/cms.py python-keystoneclient-1.7.1/keystoneclient/common/cms.py --- python-keystoneclient-1.6.0/keystoneclient/common/cms.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/common/cms.py 2015-09-09 04:34:24.000000000 +0000 @@ -26,10 +26,11 @@ import textwrap import zlib +from debtcollector import removals import six from keystoneclient import exceptions -from keystoneclient.i18n import _, _LE, _LW +from keystoneclient.i18n import _, _LE subprocess = None @@ -226,8 +227,6 @@ inform=PKIZ_CMS_FORM) -# This function is deprecated and will be removed once the ASN1 token format -# is no longer required. It is only here to be used for testing. def token_to_cms(signed_text): """Converts a custom formatted token to a PEM-formatted token. @@ -297,10 +296,14 @@ return token[:3] == PKI_ASN1_PREFIX +@removals.remove(message='Use is_asn1_token() instead.', version='1.7.0', + removal_version='2.0.0') def is_ans1_token(token): - """Deprecated. Use is_asn1_token() instead.""" - LOG.warning(_LW('The function is_ans1_token() is deprecated, ' - 'use is_asn1_token() instead.')) + """Deprecated. + + This function is deprecated as of the 1.7.0 release in favor of + :func:`is_asn1_token` and may be removed in the 2.0.0 release. + """ return is_asn1_token(token) diff -Nru python-keystoneclient-1.6.0/keystoneclient/contrib/auth/v3/oidc.py python-keystoneclient-1.7.1/keystoneclient/contrib/auth/v3/oidc.py --- python-keystoneclient-1.6.0/keystoneclient/contrib/auth/v3/oidc.py 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/contrib/auth/v3/oidc.py 2015-09-09 04:34:24.000000000 +0000 @@ -0,0 +1,209 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_config import cfg + +from keystoneclient import access +from keystoneclient.auth.identity.v3 import federated +from keystoneclient import utils + + +class OidcPassword(federated.FederatedBaseAuth): + """Implement authentication plugin for OpenID Connect protocol. + + OIDC or OpenID Connect is a protocol for federated authentication. + + The OpenID Connect specification can be found at:: + ``http://openid.net/specs/openid-connect-core-1_0.html`` + """ + + @classmethod + def get_options(cls): + options = super(OidcPassword, cls).get_options() + options.extend([ + cfg.StrOpt('username', help='Username'), + cfg.StrOpt('password', help='Password'), + cfg.StrOpt('client-id', help='OAuth 2.0 Client ID'), + cfg.StrOpt('client-secret', help='OAuth 2.0 Client Secret'), + cfg.StrOpt('access-token-endpoint', + help='OpenID Connect Provider Token Endpoint'), + cfg.StrOpt('scope', default="profile", + help='OpenID Connect scope that is requested from OP') + ]) + return options + + @utils.positional(4) + def __init__(self, auth_url, identity_provider, protocol, + username, password, client_id, client_secret, + access_token_endpoint, scope='profile', + grant_type='password'): + """The OpenID Connect plugin expects the following: + + :param auth_url: URL of the Identity Service + :type auth_url: string + + :param identity_provider: Name of the Identity Provider the client + will authenticate against + :type identity_provider: string + + :param protocol: Protocol name as configured in keystone + :type protocol: string + + :param username: Username used to authenticate + :type username: string + + :param password: Password used to authenticate + :type password: string + + :param client_id: OAuth 2.0 Client ID + :type client_id: string + + :param client_secret: OAuth 2.0 Client Secret + :type client_secret: string + + :param access_token_endpoint: OpenID Connect Provider Token Endpoint, + for example: + https://localhost:8020/oidc/OP/token + :type access_token_endpoint: string + + :param scope: OpenID Connect scope that is requested from OP, + defaults to "profile", for example: "profile email" + :type scope: string + + :param grant_type: OpenID Connect grant type, it represents the flow + that is used to talk to the OP. Valid values are: + "authorization_code", "refresh_token", or + "password". + :type grant_type: string + """ + super(OidcPassword, self).__init__(auth_url, identity_provider, + protocol) + self._username = username + self._password = password + self.client_id = client_id + self.client_secret = client_secret + self.access_token_endpoint = access_token_endpoint + self.scope = scope + self.grant_type = grant_type + + @property + def username(self): + # Override to remove deprecation. + return self._username + + @username.setter + def username(self, value): + # Override to remove deprecation. + self._username = value + + @property + def password(self): + # Override to remove deprecation. + return self._password + + @password.setter + def password(self, value): + # Override to remove deprecation. + self._password = value + + def get_unscoped_auth_ref(self, session): + """Authenticate with OpenID Connect and get back claims. + + This is a multi-step process. First an access token must be retrieved, + to do this, the username and password, the OpenID Connect client ID + and secret, and the access token endpoint must be known. + + Secondly, we then exchange the access token upon accessing the + protected Keystone endpoint (federated auth URL). This will trigger + the OpenID Connect Provider to perform a user introspection and + retrieve information (specified in the scope) about the user in + the form of an OpenID Connect Claim. These claims will be sent + to Keystone in the form of environment variables. + + :param session: a session object to send out HTTP requests. + :type session: keystoneclient.session.Session + + :returns: a token data representation + :rtype: :py:class:`keystoneclient.access.AccessInfo` + """ + + # get an access token + client_auth = (self.client_id, self.client_secret) + payload = {'grant_type': self.grant_type, 'username': self.username, + 'password': self.password, 'scope': self.scope} + response = self._get_access_token(session, client_auth, payload, + self.access_token_endpoint) + access_token = response.json()['access_token'] + + # use access token against protected URL + headers = {'Authorization': 'Bearer ' + access_token} + response = self._get_keystone_token(session, headers, + self.federated_token_url) + + # grab the unscoped token + token = response.headers['X-Subject-Token'] + token_json = response.json()['token'] + return access.AccessInfoV3(token, **token_json) + + def _get_access_token(self, session, client_auth, payload, + access_token_endpoint): + """Exchange a variety of user supplied values for an access token. + + :param session: a session object to send out HTTP requests. + :type session: keystoneclient.session.Session + + :param client_auth: a tuple representing client id and secret + :type client_auth: tuple + + :param payload: a dict containing various OpenID Connect values, for + example:: + {'grant_type': 'password', 'username': self.username, + 'password': self.password, 'scope': self.scope} + :type payload: dict + + :param access_token_endpoint: URL to use to get an access token, for + example: https://localhost/oidc/token + :type access_token_endpoint: string + """ + op_response = session.post(self.access_token_endpoint, + requests_auth=client_auth, + data=payload, + authenticated=False) + return op_response + + def _get_keystone_token(self, session, headers, federated_token_url): + """Exchange an acess token for a keystone token. + + By Sending the access token in an `Authorization: Bearer` header, to + an OpenID Connect protected endpoint (Federated Token URL). The + OpenID Connect server will use the access token to look up information + about the authenticated user (this technique is called instrospection). + The output of the instrospection will be an OpenID Connect Claim, that + will be used against the mapping engine. Should the mapping engine + succeed, a Keystone token will be presented to the user. + + :param session: a session object to send out HTTP requests. + :type session: keystoneclient.session.Session + + :param headers: an Authorization header containing the access token. + :type headers_: dict + + :param federated_auth_url: Protected URL for federated authentication, + for example: https://localhost:5000/v3/\ + OS-FEDERATION/identity_providers/bluepages/\ + protocols/oidc/auth + :type federated_auth_url: string + """ + auth_response = session.post(self.federated_token_url, + headers=headers, + authenticated=False) + return auth_response diff -Nru python-keystoneclient-1.6.0/keystoneclient/contrib/auth/v3/saml2.py python-keystoneclient-1.7.1/keystoneclient/contrib/auth/v3/saml2.py --- python-keystoneclient-1.6.0/keystoneclient/contrib/auth/v3/saml2.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/contrib/auth/v3/saml2.py 2015-09-09 04:34:24.000000000 +0000 @@ -126,7 +126,7 @@ SAML2_HEADER_INDEX = 0 ECP_SP_EMPTY_REQUEST_HEADERS = { - 'Accept': 'text/html; application/vnd.paos+xml', + 'Accept': 'text/html, application/vnd.paos+xml', 'PAOS': ('ver="urn:liberty:paos:2003-08";"urn:oasis:names:tc:' 'SAML:2.0:profiles:SSO:ecp"') } @@ -170,7 +170,27 @@ super(Saml2UnscopedToken, self).__init__(auth_url=auth_url, **kwargs) self.identity_provider = identity_provider self.identity_provider_url = identity_provider_url - self.username, self.password = username, password + self._username, self._password = username, password + + @property + def username(self): + # Override to remove deprecation. + return self._username + + @username.setter + def username(self, value): + # Override to remove deprecation. + self._username = value + + @property + def password(self): + # Override to remove deprecation. + return self._password + + @password.setter + def password(self, value): + # Override to remove deprecation. + self._password = value def _handle_http_302_ecp_redirect(self, session, response, method, **kwargs): @@ -490,7 +510,27 @@ self.identity_provider = identity_provider self.identity_provider_url = identity_provider_url self.service_provider_endpoint = service_provider_endpoint - self.username, self.password = username, password + self._username, self._password = username, password + + @property + def username(self): + # Override to remove deprecation. + return self._username + + @username.setter + def username(self, value): + # Override to remove deprecation. + self._username = value + + @property + def password(self): + # Override to remove deprecation. + return self._password + + @password.setter + def password(self, value): + # Override to remove deprecation. + self._password = value @classmethod def get_options(cls): diff -Nru python-keystoneclient-1.6.0/keystoneclient/contrib/revoke/model.py python-keystoneclient-1.7.1/keystoneclient/contrib/revoke/model.py --- python-keystoneclient-1.6.0/keystoneclient/contrib/revoke/model.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/contrib/revoke/model.py 2015-09-09 04:34:24.000000000 +0000 @@ -12,6 +12,9 @@ from oslo_utils import timeutils +from keystoneclient import utils + + # The set of attributes common between the RevokeEvent # and the dictionaries created from the token Data. _NAMES = ['trust_id', @@ -75,11 +78,11 @@ if self.consumer_id is not None: event['OS-OAUTH1:access_token_id'] = self.access_token_id if self.expires_at is not None: - event['expires_at'] = timeutils.isotime(self.expires_at, - subsecond=True) + event['expires_at'] = utils.isotime(self.expires_at, + subsecond=True) if self.issued_before is not None: - event['issued_before'] = timeutils.isotime(self.issued_before, - subsecond=True) + event['issued_before'] = utils.isotime(self.issued_before, + subsecond=True) return event def key_for_name(self, name): diff -Nru python-keystoneclient-1.6.0/keystoneclient/_discover.py python-keystoneclient-1.7.1/keystoneclient/_discover.py --- python-keystoneclient-1.6.0/keystoneclient/_discover.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/_discover.py 2015-09-09 04:34:24.000000000 +0000 @@ -195,6 +195,9 @@ :raw_status str: The status as provided by the server :rtype: list(dict) """ + if kwargs.pop('unstable', None): + kwargs.setdefault('allow_experimental', True) + kwargs.setdefault('allow_unknown', True) data = self.raw_version_data(**kwargs) versions = [] diff -Nru python-keystoneclient-1.6.0/keystoneclient/discover.py python-keystoneclient-1.7.1/keystoneclient/discover.py --- python-keystoneclient-1.6.0/keystoneclient/discover.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/discover.py 2015-09-09 04:34:24.000000000 +0000 @@ -11,7 +11,9 @@ # under the License. import logging +import warnings +from debtcollector import removals import six from keystoneclient import _discover @@ -73,7 +75,7 @@ def available_versions(url, session=None, **kwargs): """Retrieve raw version data from a url.""" if not session: - session = client_session.Session.construct(kwargs) + session = client_session.Session._construct(kwargs) return _discover.get_version_data(session, url) @@ -95,6 +97,12 @@ In the event that auth_url and endpoint is provided then auth_url will be used in accordance with how the client operates. + .. warning:: + + Creating an instance of this class without using the session argument + is deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + :param session: A session object that will be used for communication. Clients will also be constructed with this session. :type session: keystoneclient.session.Session @@ -104,35 +112,38 @@ service. (optional) :param string original_ip: The original IP of the requesting user which will be sent to identity service in a - 'Forwarded' header. (optional) DEPRECATED: use - the session object. This is ignored if a session - is provided. + 'Forwarded' header. (optional) This is ignored + if a session is provided. Deprecated as of the + 1.7.0 release and may be removed in the 2.0.0 + release. :param boolean debug: Enables debug logging of all request and responses to the identity service. default False (optional) - DEPRECATED: use the session object. This is ignored - if a session is provided. + This is ignored if a session is provided. Deprecated + as of the 1.7.0 release and may be removed in the + 2.0.0 release. :param string cacert: Path to the Privacy Enhanced Mail (PEM) file which contains the trusted authority X.509 certificates needed to established SSL connection with the - identity service. (optional) DEPRECATED: use the - session object. This is ignored if a session is - provided. + identity service. (optional) This is ignored if a + session is provided. Deprecated as of the 1.7.0 + release and may be removed in the 2.0.0 release. :param string key: Path to the Privacy Enhanced Mail (PEM) file which contains the unencrypted client private key needed to established two-way SSL connection with the identity - service. (optional) DEPRECATED: use the session object. - This is ignored if a session is provided. + service. (optional) This is ignored if a session is + provided. Deprecated as of the 1.7.0 release and may be + removed in the 2.0.0 release. :param string cert: Path to the Privacy Enhanced Mail (PEM) file which contains the corresponding X.509 client certificate needed to established two-way SSL connection with the - identity service. (optional) DEPRECATED: use the - session object. This is ignored if a session is - provided. + identity service. (optional) This is ignored if a + session is provided. Deprecated as of the 1.7.0 release + and may be removed in the 2.0.0 release. :param boolean insecure: Does not perform X.509 certificate validation when establishing SSL connection with identity service. - default: False (optional) DEPRECATED: use the - session object. This is ignored if a session is - provided. + default: False (optional) This is ignored if a + session is provided. Deprecated as of the 1.7.0 + release and may be removed in the 2.0.0 release. :param bool authenticated: Should a token be used to perform the initial discovery operations. default: None (attach a token if an auth plugin is available). @@ -142,7 +153,11 @@ @utils.positional(2) def __init__(self, session=None, authenticated=None, **kwargs): if not session: - session = client_session.Session.construct(kwargs) + warnings.warn( + 'Constructing a Discover instance without using a session is ' + 'deprecated as of the 1.7.0 release and may be removed in the ' + '2.0.0 release.', DeprecationWarning) + session = client_session.Session._construct(kwargs) kwargs['session'] = session url = None @@ -165,14 +180,19 @@ super(Discover, self).__init__(session, url, authenticated=authenticated) + @removals.remove(message='Use raw_version_data instead.', version='1.7.0', + removal_version='2.0.0') def available_versions(self, **kwargs): """Return a list of identity APIs available on the server and the data associated with them. - DEPRECATED: use raw_version_data() + .. warning:: + + This method is deprecated as of the 1.7.0 release in favor of + :meth:`raw_version_data` and may be removed in the 2.0.0 release. :param bool unstable: Accept endpoints not marked 'stable'. (optional) - DEPRECTED. Equates to setting allow_experimental + Equates to setting allow_experimental and allow_unknown to True. :param bool allow_experimental: Allow experimental version endpoints. :param bool allow_deprecated: Allow deprecated version endpoints. @@ -185,6 +205,10 @@ """ return self.raw_version_data(**kwargs) + @removals.removed_kwarg( + 'unstable', + message='Use allow_experimental and allow_unknown instead.', + version='1.7.0', removal_version='2.0.0') def raw_version_data(self, unstable=False, **kwargs): """Get raw version information from URL. @@ -192,8 +216,10 @@ on the data, so what is returned here will be the data in the same format it was received from the endpoint. - :param bool unstable: (deprecated) equates to setting - allow_experimental and allow_unknown. + :param bool unstable: equates to setting allow_experimental and + allow_unknown. This argument is deprecated as of + the 1.7.0 release and may be removed in the 2.0.0 + release. :param bool allow_experimental: Allow experimental version endpoints. :param bool allow_deprecated: Allow deprecated version endpoints. :param bool allow_unknown: Allow endpoints with an unrecognised status. diff -Nru python-keystoneclient-1.6.0/keystoneclient/exceptions.py python-keystoneclient-1.7.1/keystoneclient/exceptions.py --- python-keystoneclient-1.6.0/keystoneclient/exceptions.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/exceptions.py 2015-09-09 04:34:24.000000000 +0000 @@ -12,23 +12,453 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -""" -Exception definitions. +"""Exception definitions.""" -.. py:exception:: AuthorizationFailure +import inspect +import sys -.. py:exception:: ClientException +import six + +from keystoneclient.i18n import _ -.. py:exception:: HttpError -.. py:exception:: ValidationError +class ClientException(Exception): + """The base exception class for all exceptions this library raises. + """ + pass -.. py:exception:: Unauthorized -""" +class ValidationError(ClientException): + """Error in validation on API client side.""" + pass + + +class UnsupportedVersion(ClientException): + """User is trying to use an unsupported version of the API.""" + pass + + +class CommandError(ClientException): + """Error in CLI tool.""" + pass + + +class AuthorizationFailure(ClientException): + """Cannot authorize API client.""" + pass + + +class ConnectionError(ClientException): + """Cannot connect to API service.""" + pass + + +class ConnectionRefused(ConnectionError): + """Connection refused while trying to connect to API service.""" + pass + + +class AuthPluginOptionsMissing(AuthorizationFailure): + """Auth plugin misses some options.""" + def __init__(self, opt_names): + super(AuthPluginOptionsMissing, self).__init__( + _("Authentication failed. Missing options: %s") % + ", ".join(opt_names)) + self.opt_names = opt_names + + +class AuthSystemNotFound(AuthorizationFailure): + """User has specified an AuthSystem that is not installed.""" + def __init__(self, auth_system): + super(AuthSystemNotFound, self).__init__( + _("AuthSystemNotFound: %r") % auth_system) + self.auth_system = auth_system + + +class NoUniqueMatch(ClientException): + """Multiple entities found instead of one.""" + pass + + +class EndpointException(ClientException): + """Something is rotten in Service Catalog.""" + pass + + +class EndpointNotFound(EndpointException): + """Could not find requested endpoint in Service Catalog.""" + pass + + +class AmbiguousEndpoints(EndpointException): + """Found more than one matching endpoint in Service Catalog.""" + def __init__(self, endpoints=None): + super(AmbiguousEndpoints, self).__init__( + _("AmbiguousEndpoints: %r") % endpoints) + self.endpoints = endpoints + + +class HttpError(ClientException): + """The base exception class for all HTTP exceptions. + """ + http_status = 0 + message = _("HTTP Error") + + def __init__(self, message=None, details=None, + response=None, request_id=None, + url=None, method=None, http_status=None): + self.http_status = http_status or self.http_status + self.message = message or self.message + self.details = details + self.request_id = request_id + self.response = response + self.url = url + self.method = method + formatted_string = "%s (HTTP %s)" % (self.message, self.http_status) + if request_id: + formatted_string += " (Request-ID: %s)" % request_id + super(HttpError, self).__init__(formatted_string) + + +class HTTPRedirection(HttpError): + """HTTP Redirection.""" + message = _("HTTP Redirection") + + +class HTTPClientError(HttpError): + """Client-side HTTP error. + + Exception for cases in which the client seems to have erred. + """ + message = _("HTTP Client Error") + + +class HttpServerError(HttpError): + """Server-side HTTP error. + + Exception for cases in which the server is aware that it has + erred or is incapable of performing the request. + """ + message = _("HTTP Server Error") + + +class MultipleChoices(HTTPRedirection): + """HTTP 300 - Multiple Choices. + + Indicates multiple options for the resource that the client may follow. + """ + + http_status = 300 + message = _("Multiple Choices") + + +class BadRequest(HTTPClientError): + """HTTP 400 - Bad Request. + + The request cannot be fulfilled due to bad syntax. + """ + http_status = 400 + message = _("Bad Request") + + +class Unauthorized(HTTPClientError): + """HTTP 401 - Unauthorized. + + Similar to 403 Forbidden, but specifically for use when authentication + is required and has failed or has not yet been provided. + """ + http_status = 401 + message = _("Unauthorized") + + +class PaymentRequired(HTTPClientError): + """HTTP 402 - Payment Required. + + Reserved for future use. + """ + http_status = 402 + message = _("Payment Required") + + +class Forbidden(HTTPClientError): + """HTTP 403 - Forbidden. + + The request was a valid request, but the server is refusing to respond + to it. + """ + http_status = 403 + message = _("Forbidden") + + +class NotFound(HTTPClientError): + """HTTP 404 - Not Found. + + The requested resource could not be found but may be available again + in the future. + """ + http_status = 404 + message = _("Not Found") + + +class MethodNotAllowed(HTTPClientError): + """HTTP 405 - Method Not Allowed. + + A request was made of a resource using a request method not supported + by that resource. + """ + http_status = 405 + message = _("Method Not Allowed") + + +class NotAcceptable(HTTPClientError): + """HTTP 406 - Not Acceptable. + + The requested resource is only capable of generating content not + acceptable according to the Accept headers sent in the request. + """ + http_status = 406 + message = _("Not Acceptable") + + +class ProxyAuthenticationRequired(HTTPClientError): + """HTTP 407 - Proxy Authentication Required. + + The client must first authenticate itself with the proxy. + """ + http_status = 407 + message = _("Proxy Authentication Required") + + +class RequestTimeout(HTTPClientError): + """HTTP 408 - Request Timeout. + + The server timed out waiting for the request. + """ + http_status = 408 + message = _("Request Timeout") + + +class Conflict(HTTPClientError): + """HTTP 409 - Conflict. + + Indicates that the request could not be processed because of conflict + in the request, such as an edit conflict. + """ + http_status = 409 + message = _("Conflict") + + +class Gone(HTTPClientError): + """HTTP 410 - Gone. + + Indicates that the resource requested is no longer available and will + not be available again. + """ + http_status = 410 + message = _("Gone") + + +class LengthRequired(HTTPClientError): + """HTTP 411 - Length Required. + + The request did not specify the length of its content, which is + required by the requested resource. + """ + http_status = 411 + message = _("Length Required") + + +class PreconditionFailed(HTTPClientError): + """HTTP 412 - Precondition Failed. + + The server does not meet one of the preconditions that the requester + put on the request. + """ + http_status = 412 + message = _("Precondition Failed") + + +class RequestEntityTooLarge(HTTPClientError): + """HTTP 413 - Request Entity Too Large. + + The request is larger than the server is willing or able to process. + """ + http_status = 413 + message = _("Request Entity Too Large") + + def __init__(self, *args, **kwargs): + try: + self.retry_after = int(kwargs.pop('retry_after')) + except (KeyError, ValueError): + self.retry_after = 0 + + super(RequestEntityTooLarge, self).__init__(*args, **kwargs) + + +class RequestUriTooLong(HTTPClientError): + """HTTP 414 - Request-URI Too Long. + + The URI provided was too long for the server to process. + """ + http_status = 414 + message = _("Request-URI Too Long") + + +class UnsupportedMediaType(HTTPClientError): + """HTTP 415 - Unsupported Media Type. + + The request entity has a media type which the server or resource does + not support. + """ + http_status = 415 + message = _("Unsupported Media Type") + + +class RequestedRangeNotSatisfiable(HTTPClientError): + """HTTP 416 - Requested Range Not Satisfiable. + + The client has asked for a portion of the file, but the server cannot + supply that portion. + """ + http_status = 416 + message = _("Requested Range Not Satisfiable") + + +class ExpectationFailed(HTTPClientError): + """HTTP 417 - Expectation Failed. + + The server cannot meet the requirements of the Expect request-header field. + """ + http_status = 417 + message = _("Expectation Failed") + + +class UnprocessableEntity(HTTPClientError): + """HTTP 422 - Unprocessable Entity. + + The request was well-formed but was unable to be followed due to semantic + errors. + """ + http_status = 422 + message = _("Unprocessable Entity") + + +class InternalServerError(HttpServerError): + """HTTP 500 - Internal Server Error. + + A generic error message, given when no more specific message is suitable. + """ + http_status = 500 + message = _("Internal Server Error") + + +# NotImplemented is a python keyword. +class HttpNotImplemented(HttpServerError): + """HTTP 501 - Not Implemented. + + The server either does not recognize the request method, or it lacks + the ability to fulfill the request. + """ + http_status = 501 + message = _("Not Implemented") + + +class BadGateway(HttpServerError): + """HTTP 502 - Bad Gateway. + + The server was acting as a gateway or proxy and received an invalid + response from the upstream server. + """ + http_status = 502 + message = _("Bad Gateway") + + +class ServiceUnavailable(HttpServerError): + """HTTP 503 - Service Unavailable. + + The server is currently unavailable. + """ + http_status = 503 + message = _("Service Unavailable") + + +class GatewayTimeout(HttpServerError): + """HTTP 504 - Gateway Timeout. + + The server was acting as a gateway or proxy and did not receive a timely + response from the upstream server. + """ + http_status = 504 + message = _("Gateway Timeout") + + +class HttpVersionNotSupported(HttpServerError): + """HTTP 505 - HttpVersion Not Supported. + + The server does not support the HTTP protocol version used in the request. + """ + http_status = 505 + message = _("HTTP Version Not Supported") + + +# _code_map contains all the classes that have http_status attribute. +_code_map = dict( + (getattr(obj, 'http_status', None), obj) + for name, obj in six.iteritems(vars(sys.modules[__name__])) + if inspect.isclass(obj) and getattr(obj, 'http_status', False) +) + + +def from_response(response, method, url): + """Returns an instance of :class:`HttpError` or subclass based on response. + + :param response: instance of `requests.Response` class + :param method: HTTP method used for request + :param url: URL used for request + """ + + req_id = response.headers.get("x-openstack-request-id") + # NOTE(hdd) true for older versions of nova and cinder + if not req_id: + req_id = response.headers.get("x-compute-request-id") + kwargs = { + "http_status": response.status_code, + "response": response, + "method": method, + "url": url, + "request_id": req_id, + } + if "retry-after" in response.headers: + kwargs["retry_after"] = response.headers["retry-after"] + + content_type = response.headers.get("Content-Type", "") + if content_type.startswith("application/json"): + try: + body = response.json() + except ValueError: + pass + else: + if isinstance(body, dict): + error = body.get(list(body)[0]) + if isinstance(error, dict): + kwargs["message"] = (error.get("message") or + error.get("faultstring")) + kwargs["details"] = (error.get("details") or + six.text_type(body)) + elif content_type.startswith("text/"): + kwargs["details"] = getattr(response, 'text', '') + + try: + cls = _code_map[response.status_code] + except KeyError: + if 500 <= response.status_code < 600: + cls = HttpServerError + elif 400 <= response.status_code < 500: + cls = HTTPClientError + else: + cls = HttpError + return cls(**kwargs) -from keystoneclient.i18n import _ -from keystoneclient.openstack.common.apiclient.exceptions import * # noqa # NOTE(akurilin): This alias should be left here to support backwards # compatibility until we are sure that usage of these exceptions in @@ -97,6 +527,23 @@ super(NoMatchingPlugin, self).__init__(msg) +class UnsupportedParameters(ClientException): + """A parameter that was provided or returned is not supported. + + :param list(str) names: Names of the unsupported parameters. + + .. py:attribute:: names + + Names of the unsupported parameters. + """ + + def __init__(self, names): + self.names = names + + m = _('The following parameters were given that are unsupported: %s') + super(UnsupportedParameters, self).__init__(m % ', '.join(self.names)) + + class InvalidResponse(ClientException): """The response from the server is not valid for this request.""" diff -Nru python-keystoneclient-1.6.0/keystoneclient/fixture/discovery.py python-keystoneclient-1.7.1/keystoneclient/fixture/discovery.py --- python-keystoneclient-1.6.0/keystoneclient/fixture/discovery.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/fixture/discovery.py 2015-09-09 04:34:24.000000000 +0000 @@ -77,7 +77,7 @@ @updated.setter def updated(self, value): - self.updated_str = timeutils.isotime(value) + self.updated_str = utils.isotime(value) @utils.positional() def add_link(self, href, rel='self', type=None): diff -Nru python-keystoneclient-1.6.0/keystoneclient/fixture/__init__.py python-keystoneclient-1.7.1/keystoneclient/fixture/__init__.py --- python-keystoneclient-1.6.0/keystoneclient/fixture/__init__.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/fixture/__init__.py 2015-09-09 04:34:24.000000000 +0000 @@ -22,10 +22,15 @@ """ from keystoneclient.fixture.discovery import * # noqa -from keystoneclient.fixture.exception import FixtureValidationError # noqa -from keystoneclient.fixture.v2 import Token as V2Token # noqa -from keystoneclient.fixture.v3 import Token as V3Token # noqa -from keystoneclient.fixture.v3 import V3FederationToken # noqa +from keystoneclient.fixture import exception +from keystoneclient.fixture import v2 +from keystoneclient.fixture import v3 + + +FixtureValidationError = exception.FixtureValidationError +V2Token = v2.Token +V3Token = v3.Token +V3FederationToken = v3.V3FederationToken __all__ = ['DiscoveryList', 'FixtureValidationError', diff -Nru python-keystoneclient-1.6.0/keystoneclient/fixture/v2.py python-keystoneclient-1.7.1/keystoneclient/fixture/v2.py --- python-keystoneclient-1.6.0/keystoneclient/fixture/v2.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/fixture/v2.py 2015-09-09 04:34:24.000000000 +0000 @@ -16,6 +16,7 @@ from oslo_utils import timeutils from keystoneclient.fixture import exception +from keystoneclient import utils class _Service(dict): @@ -112,7 +113,7 @@ @expires.setter def expires(self, value): - self.expires_str = timeutils.isotime(value) + self.expires_str = utils.isotime(value) @property def issued_str(self): @@ -128,7 +129,7 @@ @issued.setter def issued(self, value): - self.issued_str = timeutils.isotime(value) + self.issued_str = utils.isotime(value) @property def _user(self): diff -Nru python-keystoneclient-1.6.0/keystoneclient/fixture/v3.py python-keystoneclient-1.7.1/keystoneclient/fixture/v3.py --- python-keystoneclient-1.6.0/keystoneclient/fixture/v3.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/fixture/v3.py 2015-09-09 04:34:24.000000000 +0000 @@ -16,6 +16,7 @@ from oslo_utils import timeutils from keystoneclient.fixture import exception +from keystoneclient import utils class _Service(dict): @@ -136,7 +137,7 @@ @expires.setter def expires(self, value): - self.expires_str = timeutils.isotime(value, subsecond=True) + self.expires_str = utils.isotime(value, subsecond=True) @property def issued_str(self): @@ -152,7 +153,7 @@ @issued.setter def issued(self, value): - self.issued_str = timeutils.isotime(value, subsecond=True) + self.issued_str = utils.isotime(value, subsecond=True) @property def _user(self): @@ -324,6 +325,14 @@ def audit_chain_id(self, value): self.root['audit_ids'] = [self.audit_id, value] + @property + def role_ids(self): + return [r['id'] for r in self.root.get('roles', [])] + + @property + def role_names(self): + return [r['name'] for r in self.root.get('roles', [])] + def validate(self): project = self.root.get('project') domain = self.root.get('domain') diff -Nru python-keystoneclient-1.6.0/keystoneclient/generic/client.py python-keystoneclient-1.7.1/keystoneclient/generic/client.py --- python-keystoneclient-1.6.0/keystoneclient/generic/client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/generic/client.py 2015-09-09 04:34:24.000000000 +0000 @@ -84,9 +84,9 @@ def _check_keystone_versions(self, url): """Calls Keystone URL and detects the available API versions.""" try: - resp, body = self.request(url, "GET", - headers={'Accept': - 'application/json'}) + resp, body = self._request(url, "GET", + headers={'Accept': + 'application/json'}) # Multiple Choices status code is returned by the root # identity endpoint, with references to one or more # Identity API versions -- v3 spec @@ -148,9 +148,9 @@ try: if not url.endswith("/"): url += '/' - resp, body = self.request("%sextensions" % url, "GET", - headers={'Accept': - 'application/json'}) + resp, body = self._request("%sextensions" % url, "GET", + headers={'Accept': + 'application/json'}) if resp.status_code in (200, 204): # some cases we get No Content if 'extensions' in body and 'values' in body['extensions']: # Parse correct format (per contract) diff -Nru python-keystoneclient-1.6.0/keystoneclient/httpclient.py python-keystoneclient-1.7.1/keystoneclient/httpclient.py --- python-keystoneclient-1.6.0/keystoneclient/httpclient.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/httpclient.py 2015-09-09 04:34:24.000000000 +0000 @@ -20,7 +20,10 @@ """ import logging +import warnings +from debtcollector import removals +from debtcollector import renames from oslo_serialization import jsonutils import pkg_resources import requests @@ -64,10 +67,25 @@ _logger = logging.getLogger(__name__) -# These variables are moved and using them via httpclient is deprecated. -# Maintain here for compatibility. USER_AGENT = client_session.USER_AGENT -request = client_session.request +"""Default user agent string. + +This property is deprecated as of the 1.7.0 release in favor of +:data:`keystoneclient.session.USER_AGENT` and may be removed in the 2.0.0 +release. +""" + + +@removals.remove(message='Use keystoneclient.session.request instead.', + version='1.7.0', removal_version='2.0.0') +def request(*args, **kwargs): + """Make a request. + + This function is deprecated as of the 1.7.0 release in favor of + :func:`keystoneclient.session.request` and may be removed in the + 2.0.0 release. + """ + return client_session.request(*args, **kwargs) class _FakeRequestSession(object): @@ -134,6 +152,12 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin): """HTTP client + .. warning:: + + Creating an instance of this class without using the session argument + is deprecated as of the 1.7.0 release and may be removed in the 2.0.0 + release. + :param string user_id: User ID for authentication. (optional) :param string username: Username for authentication. (optional) :param string user_domain_id: User's domain ID for authentication. @@ -152,18 +176,32 @@ :param string auth_url: Identity service endpoint for authorization. :param string region_name: Name of a region to select when choosing an endpoint from the service catalog. - :param integer timeout: DEPRECATED: use session. (optional) + :param integer timeout: This argument is deprecated as of the 1.7.0 release + in favor of session and may be removed in the 2.0.0 + release. (optional) :param string endpoint: A user-supplied endpoint URL for the identity service. Lazy-authentication is possible for API service calls if endpoint is set at instantiation. (optional) :param string token: Token for authentication. (optional) - :param string cacert: DEPRECATED: use session. (optional) - :param string key: DEPRECATED: use session. (optional) - :param string cert: DEPRECATED: use session. (optional) - :param boolean insecure: DEPRECATED: use session. (optional) - :param string original_ip: DEPRECATED: use session. (optional) - :param boolean debug: DEPRECATED: use logging configuration. (optional) + :param string cacert: This argument is deprecated as of the 1.7.0 release + in favor of session and may be removed in the 2.0.0 + release. (optional) + :param string key: This argument is deprecated as of the 1.7.0 release + in favor of session and may be removed in the 2.0.0 + release. (optional) + :param string cert: This argument is deprecated as of the 1.7.0 release + in favor of session and may be removed in the 2.0.0 + release. (optional) + :param boolean insecure: This argument is deprecated as of the 1.7.0 + release in favor of session and may be removed in + the 2.0.0 release. (optional) + :param string original_ip: This argument is deprecated as of the 1.7.0 + release in favor of session and may be removed + in the 2.0.0 release. (optional) + :param boolean debug: This argument is deprecated as of the 1.7.0 release + in favor of logging configuration and may be removed + in the 2.0.0 release. (optional) :param dict auth_ref: To allow for consumers of the client to manage their own caching strategy, you may initialize a client with a previously captured auth_reference (token). If @@ -178,10 +216,13 @@ keyring is about to expire. default: 30 (optional) :param string tenant_name: Tenant name. (optional) The tenant_name keyword - argument is deprecated, use project_name - instead. + argument is deprecated as of the 1.7.0 release + in favor of project_name and may be removed in + the 2.0.0 release. :param string tenant_id: Tenant id. (optional) The tenant_id keyword - argument is deprecated, use project_id instead. + argument is deprecated as of the 1.7.0 release in + favor of project_id and may be removed in the + 2.0.0 release. :param string trust_id: Trust ID for trust scoping. (optional) :param object session: A Session object to be used for communicating with the identity service. @@ -204,6 +245,10 @@ version = None + @renames.renamed_kwarg('tenant_name', 'project_name', version='1.7.0', + removal_version='2.0.0') + @renames.renamed_kwarg('tenant_id', 'project_id', version='1.7.0', + removal_version='2.0.0') @utils.positional(enforcement=utils.positional.WARN) def __init__(self, username=None, tenant_id=None, tenant_name=None, password=None, auth_url=None, region_name=None, endpoint=None, @@ -248,12 +293,23 @@ self.project_id = self.auth_ref.project_id self.project_name = self.auth_ref.project_name self.project_domain_id = self.auth_ref.project_domain_id - self.auth_url = self.auth_ref.auth_url[0] - self._management_url = self.auth_ref.management_url[0] + auth_urls = self.auth_ref.service_catalog.get_urls( + service_type='identity', endpoint_type='public', + region_name=region_name) + self.auth_url = auth_urls[0] + management_urls = self.auth_ref.service_catalog.get_urls( + service_type='identity', endpoint_type='admin', + region_name=region_name) + self._management_url = management_urls[0] self.auth_token_from_user = self.auth_ref.auth_token self.trust_id = self.auth_ref.trust_id + + # TODO(blk-u): Using self.auth_ref.service_catalog._region_name is + # deprecated and this code must be removed when the property is + # actually removed. if self.auth_ref.has_service_catalog() and not region_name: - region_name = self.auth_ref.service_catalog.region_name + region_name = self.auth_ref.service_catalog._region_name + else: self.auth_ref = None @@ -313,8 +369,14 @@ self._auth_token = None if not session: + + warnings.warn( + 'Constructing an HTTPClient instance without using a session ' + 'is deprecated as of the 1.7.0 release and may be removed in ' + 'the 2.0.0 release.', DeprecationWarning) + kwargs['session'] = _FakeRequestSession() - session = client_session.Session.construct(kwargs) + session = client_session.Session._construct(kwargs) session.auth = self super(HTTPClient, self).__init__(session=session) @@ -398,15 +460,35 @@ @property def tenant_id(self): """Provide read-only backwards compatibility for tenant_id. - This is deprecated, use project_id instead. + + .. warning:: + + This is deprecated as of the 1.7.0 release in favor of project_id + and may be removed in the 2.0.0 release. """ + + warnings.warn( + 'tenant_id is deprecated as of the 1.7.0 release in favor of ' + 'project_id and may be removed in the 2.0.0 release.', + DeprecationWarning) + return self.project_id @property def tenant_name(self): """Provide read-only backwards compatibility for tenant_name. - This is deprecated, use project_name instead. + + .. warning:: + + This is deprecated as of the 1.7.0 release in favor of project_name + and may be removed in the 2.0.0 release. """ + + warnings.warn( + 'tenant_name is deprecated as of the 1.7.0 release in favor of ' + 'project_name and may be removed in the 2.0.0 release.', + DeprecationWarning) + return self.project_name @utils.positional(enforcement=utils.positional.WARN) @@ -532,7 +614,7 @@ Returns a slash-separated string of values ordered by key name. """ - return '/'.join([kwargs[k] or '?' for k in sorted(kwargs.keys())]) + return '/'.join([kwargs[k] or '?' for k in sorted(kwargs)]) def get_auth_ref_from_keyring(self, **kwargs): """Retrieve auth_ref from keyring. @@ -552,7 +634,7 @@ auth_ref = keyring.get_password("keystoneclient_auth", keyring_key) if auth_ref: - auth_ref = pickle.loads(auth_ref) + auth_ref = pickle.loads(auth_ref) # nosec if auth_ref.will_expire_soon(self.stale_duration): # token has expired, don't use it auth_ref = None @@ -649,6 +731,7 @@ def serialize(self, entity): return jsonutils.dumps(entity) + @removals.remove(version='1.7.0', removal_version='2.0.0') def request(self, *args, **kwargs): """Send an http request with the specified characteristics. @@ -656,10 +739,15 @@ setting headers, JSON encoding/decoding, and error handling. .. warning:: + *DEPRECATED*: This function is no longer used. It was designed to be used only by the managers and the managers now receive an adapter so this function is no longer on the standard request path. + This may be removed in the 2.0.0 release. """ + return self._request(*args, **kwargs) + + def _request(self, *args, **kwargs): kwargs.setdefault('authenticated', False) return self._adapter.request(*args, **kwargs) @@ -668,15 +756,14 @@ concatenating self.management_url and url and passing in method and any associated kwargs. """ - # NOTE(jamielennox): This is deprecated and is no longer a part of the - # standard client request path. It now goes via the adapter instead. if not management: endpoint_filter = kwargs.setdefault('endpoint_filter', {}) endpoint_filter.setdefault('interface', 'public') kwargs.setdefault('authenticated', None) - return self.request(url, method, **kwargs) + return self._request(url, method, **kwargs) + @removals.remove(version='1.7.0', removal_version='2.0.0') def get(self, url, **kwargs): """Perform an authenticated GET request. @@ -684,12 +771,16 @@ authentication token if one is available. .. warning:: - *DEPRECATED*: This function is no longer used. It was designed to - be used by the managers and the managers now receive an adapter so - this function is no longer on the standard request path. + + *DEPRECATED*: This function is no longer used and is deprecated as + of the 1.7.0 release and may be removed in the 2.0.0 release. It + was designed to be used by the managers and the managers now + receive an adapter so this function is no longer on the standard + request path. """ return self._cs_request(url, 'GET', **kwargs) + @removals.remove(version='1.7.0', removal_version='2.0.0') def head(self, url, **kwargs): """Perform an authenticated HEAD request. @@ -697,12 +788,16 @@ authentication token if one is available. .. warning:: - *DEPRECATED*: This function is no longer used. It was designed to - be used by the managers and the managers now receive an adapter so - this function is no longer on the standard request path. + + *DEPRECATED*: This function is no longer used and is deprecated as + of the 1.7.0 release and may be removed in the 2.0.0 release. It + was designed to be used by the managers and the managers now + receive an adapter so this function is no longer on the standard + request path. """ return self._cs_request(url, 'HEAD', **kwargs) + @removals.remove(version='1.7.0', removal_version='2.0.0') def post(self, url, **kwargs): """Perform an authenticate POST request. @@ -710,12 +805,16 @@ authentication token if one is available. .. warning:: - *DEPRECATED*: This function is no longer used. It was designed to - be used by the managers and the managers now receive an adapter so - this function is no longer on the standard request path. + + *DEPRECATED*: This function is no longer used and is deprecated as + of the 1.7.0 release and may be removed in the 2.0.0 release. It + was designed to be used by the managers and the managers now + receive an adapter so this function is no longer on the standard + request path. """ return self._cs_request(url, 'POST', **kwargs) + @removals.remove(version='1.7.0', removal_version='2.0.0') def put(self, url, **kwargs): """Perform an authenticate PUT request. @@ -723,12 +822,16 @@ authentication token if one is available. .. warning:: - *DEPRECATED*: This function is no longer used. It was designed to - be used by the managers and the managers now receive an adapter so - this function is no longer on the standard request path. + + *DEPRECATED*: This function is no longer used and is deprecated as + of the 1.7.0 release and may be removed in the 2.0.0 release. It + was designed to be used by the managers and the managers now + receive an adapter so this function is no longer on the standard + request path. """ return self._cs_request(url, 'PUT', **kwargs) + @removals.remove(version='1.7.0', removal_version='2.0.0') def patch(self, url, **kwargs): """Perform an authenticate PATCH request. @@ -736,12 +839,16 @@ an authentication token if one is available. .. warning:: - *DEPRECATED*: This function is no longer used. It was designed to - be used by the managers and the managers now receive an adapter so - this function is no longer on the standard request path. + + *DEPRECATED*: This function is no longer used and is deprecated as + of the 1.7.0 release and may be removed in the 2.0.0 release. It + was designed to be used by the managers and the managers now + receive an adapter so this function is no longer on the standard + request path. """ return self._cs_request(url, 'PATCH', **kwargs) + @removals.remove(version='1.7.0', removal_version='2.0.0') def delete(self, url, **kwargs): """Perform an authenticate DELETE request. @@ -749,15 +856,15 @@ an authentication token if one is available. .. warning:: - *DEPRECATED*: This function is no longer used. It was designed to - be used by the managers and the managers now receive an adapter so - this function is no longer on the standard request path. + + *DEPRECATED*: This function is no longer used and is deprecated as + of the 1.7.0 release and may be removed in the 2.0.0 release. It + was designed to be used by the managers and the managers now + receive an adapter so this function is no longer on the standard + request path. """ return self._cs_request(url, 'DELETE', **kwargs) - # DEPRECATIONS: The following methods are no longer directly supported - # but maintained for compatibility purposes. - deprecated_session_variables = {'original_ip': None, 'cert': None, 'timeout': None, @@ -766,12 +873,15 @@ deprecated_adapter_variables = {'region_name': None} def __getattr__(self, name): - # FIXME(jamielennox): provide a proper deprecated warning try: var_name = self.deprecated_session_variables[name] except KeyError: pass else: + warnings.warn( + 'The %s session variable is deprecated as of the 1.7.0 ' + 'release and may be removed in the 2.0.0 release' % name, + DeprecationWarning) return getattr(self.session, var_name or name) try: @@ -779,17 +889,24 @@ except KeyError: pass else: + warnings.warn( + 'The %s adapter variable is deprecated as of the 1.7.0 ' + 'release and may be removed in the 2.0.0 release' % name, + DeprecationWarning) return getattr(self._adapter, var_name or name) raise AttributeError(_("Unknown Attribute: %s") % name) def __setattr__(self, name, val): - # FIXME(jamielennox): provide a proper deprecated warning try: var_name = self.deprecated_session_variables[name] except KeyError: pass else: + warnings.warn( + 'The %s session variable is deprecated as of the 1.7.0 ' + 'release and may be removed in the 2.0.0 release' % name, + DeprecationWarning) return setattr(self.session, var_name or name) try: @@ -797,6 +914,10 @@ except KeyError: pass else: + warnings.warn( + 'The %s adapter variable is deprecated as of the 1.7.0 ' + 'release and may be removed in the 2.0.0 release' % name, + DeprecationWarning) return setattr(self._adapter, var_name or name) super(HTTPClient, self).__setattr__(name, val) diff -Nru python-keystoneclient-1.6.0/keystoneclient/middleware/auth_token.py python-keystoneclient-1.7.1/keystoneclient/middleware/auth_token.py --- python-keystoneclient-1.6.0/keystoneclient/middleware/auth_token.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/middleware/auth_token.py 2015-09-09 04:34:24.000000000 +0000 @@ -169,6 +169,7 @@ from keystoneclient import exceptions from keystoneclient.middleware import memcache_crypt from keystoneclient.openstack.common import memorycache +from keystoneclient import utils # alternative middleware configuration in the main application's @@ -382,7 +383,7 @@ utcnow = timeutils.utcnow() if utcnow >= expires: raise InvalidUserToken('Token authorization failed') - return timeutils.isotime(at=expires, subsecond=True) + return utils.isotime(at=expires, subsecond=True) def _v3_to_v2_catalog(catalog): @@ -750,8 +751,8 @@ return token else: if not self.delay_auth_decision: - self.LOG.warn('Unable to find authentication token' - ' in headers') + self.LOG.warning('Unable to find authentication token' + ' in headers') self.LOG.debug('Headers: %s', env) raise InvalidUserToken('Unable to find token in headers') @@ -804,8 +805,8 @@ if self.cert_file and self.key_file: kwargs['cert'] = (self.cert_file, self.key_file) elif self.cert_file or self.key_file: - self.LOG.warn('Cannot use only a cert or key file. ' - 'Please provide both. Ignoring.') + self.LOG.warning('Cannot use only a cert or key file. ' + 'Please provide both. Ignoring.') kwargs['verify'] = self.ssl_ca_file or True if self.ssl_insecure: @@ -822,7 +823,8 @@ self.LOG.error('HTTP connection exception: %s', e) raise NetworkError('Unable to communicate with keystone') # NOTE(vish): sleep 0.5, 1, 2 - self.LOG.warn('Retrying on HTTP connection exception: %s', e) + self.LOG.warning('Retrying on HTTP connection exception: %s', + e) time.sleep(2.0 ** retry / 2) retry += 1 @@ -896,12 +898,12 @@ datetime_expiry = timeutils.parse_isotime(expiry) return (token, timeutils.normalize_time(datetime_expiry)) except (AssertionError, KeyError): - self.LOG.warn( + self.LOG.warning( 'Unexpected response from keystone service: %s', data) raise ServiceError('invalid json response') except (ValueError): data['access']['token']['id'] = '' - self.LOG.warn( + self.LOG.warning( 'Unable to parse expiration time from token: %s', data) raise ServiceError('invalid json response') @@ -948,13 +950,13 @@ return data except NetworkError: self.LOG.debug('Token validation failure.', exc_info=True) - self.LOG.warn('Authorization failed for token') + self.LOG.warning('Authorization failed for token') raise InvalidUserToken('Token authorization failed') except Exception: self.LOG.debug('Token validation failure.', exc_info=True) if token_id: self._token_cache.store_invalid(token_id) - self.LOG.warn('Authorization failed for token') + self.LOG.warning('Authorization failed for token') raise InvalidUserToken('Token authorization failed') def _build_user_headers(self, token_info): @@ -1143,7 +1145,7 @@ if response.status_code == 200: return data if response.status_code == 404: - self.LOG.warn('Authorization failed for token') + self.LOG.warning('Authorization failed for token') raise InvalidUserToken('Token authorization failed') if response.status_code == 401: self.LOG.info( @@ -1156,7 +1158,7 @@ self.LOG.info('Retrying validation') return self.verify_uuid_token(user_token, False) else: - self.LOG.warn('Invalid user token. Keystone response: %s', data) + self.LOG.warning('Invalid user token. Keystone response: %s', data) raise InvalidUserToken() diff -Nru python-keystoneclient-1.6.0/keystoneclient/middleware/s3_token.py python-keystoneclient-1.7.1/keystoneclient/middleware/s3_token.py --- python-keystoneclient-1.6.0/keystoneclient/middleware/s3_token.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/middleware/s3_token.py 2015-09-09 04:34:24.000000000 +0000 @@ -22,6 +22,12 @@ """ S3 TOKEN MIDDLEWARE +.. warning:: + + This module is DEPRECATED and may be removed in the 2.0.0 release. The + s3_token middleware has been moved to the `keystonemiddleware repository + `_. + This WSGI component: * Get a request from the swift3 middleware with an S3 Authorization diff -Nru python-keystoneclient-1.6.0/keystoneclient/openstack/common/apiclient/base.py python-keystoneclient-1.7.1/keystoneclient/openstack/common/apiclient/base.py --- python-keystoneclient-1.6.0/keystoneclient/openstack/common/apiclient/base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/openstack/common/apiclient/base.py 2015-09-09 04:34:24.000000000 +0000 @@ -33,18 +33,22 @@ # ######################################################################## +######################################################################## +# NOTE(blk-u): This module is not being synced with oslo-incubator +# anymore. We need to deprecate property and get rid of it. +######################################################################## + # E1102: %s is not callable # pylint: disable=E1102 import abc -import copy -from oslo_utils import strutils import six from six.moves.urllib import parse from keystoneclient.openstack.common._i18n import _ +from keystoneclient import base as _base from keystoneclient.openstack.common.apiclient import exceptions @@ -437,96 +441,4 @@ return "" % self.name -class Resource(object): - """Base class for OpenStack resources (tenant, user, etc.). - - This is pretty much just a bag for attributes. - """ - - HUMAN_ID = False - NAME_ATTR = 'name' - - def __init__(self, manager, info, loaded=False): - """Populate and bind to a manager. - - :param manager: BaseManager object - :param info: dictionary representing resource attributes - :param loaded: prevent lazy-loading if set to True - """ - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def __repr__(self): - reprkeys = sorted(k - for k in self.__dict__.keys() - if k[0] != '_' and k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - @property - def human_id(self): - """Human-readable ID which can be used for bash completion. - """ - if self.HUMAN_ID: - name = getattr(self, self.NAME_ATTR, None) - if name is not None: - return strutils.to_slug(name) - return None - - def _add_details(self, info): - for (k, v) in six.iteritems(info): - try: - setattr(self, k, v) - self._info[k] = v - except AttributeError: - # In this case we already defined the attribute on the class - pass - - def __getattr__(self, k): - if k not in self.__dict__: - # NOTE(bcwaldon): disallow lazy-loading if already loaded once - if not self.is_loaded(): - self.get() - return self.__getattr__(k) - - raise AttributeError(k) - else: - return self.__dict__[k] - - def get(self): - """Support for lazy loading details. - - Some clients, such as novaclient have the option to lazy load the - details, details which can be loaded with this function. - """ - # set_loaded() first ... so if we have to bail, we know we tried. - self.set_loaded(True) - if not hasattr(self.manager, 'get'): - return - - new = self.manager.get(self.id) - if new: - self._add_details(new._info) - self._add_details( - {'x_request_id': self.manager.client.last_request_id}) - - def __eq__(self, other): - if not isinstance(other, Resource): - return NotImplemented - # two resources of different types are not equal - if not isinstance(other, self.__class__): - return False - if hasattr(self, 'id') and hasattr(other, 'id'): - return self.id == other.id - return self._info == other._info - - def is_loaded(self): - return self._loaded - - def set_loaded(self, val): - self._loaded = val - - def to_dict(self): - return copy.deepcopy(self._info) +Resource = _base.Resource diff -Nru python-keystoneclient-1.6.0/keystoneclient/openstack/common/apiclient/exceptions.py python-keystoneclient-1.7.1/keystoneclient/openstack/common/apiclient/exceptions.py --- python-keystoneclient-1.6.0/keystoneclient/openstack/common/apiclient/exceptions.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/openstack/common/apiclient/exceptions.py 2015-09-09 04:34:24.000000000 +0000 @@ -33,447 +33,61 @@ # ######################################################################## -import inspect -import sys - -import six +######################################################################## +# +# THIS MODULE IS NOT SYNCED WITH OSLO-INCUBATOR. +# WE'RE JUST TRYING TO GET RID OF IT. +# +######################################################################## from keystoneclient.openstack.common._i18n import _ +from keystoneclient import exceptions -class ClientException(Exception): - """The base exception class for all exceptions this library raises. - """ - pass - - -class ValidationError(ClientException): - """Error in validation on API client side.""" - pass - - -class UnsupportedVersion(ClientException): - """User is trying to use an unsupported version of the API.""" - pass - - -class CommandError(ClientException): - """Error in CLI tool.""" - pass - - -class AuthorizationFailure(ClientException): - """Cannot authorize API client.""" - pass - - -class ConnectionError(ClientException): - """Cannot connect to API service.""" - pass - - -class ConnectionRefused(ConnectionError): - """Connection refused while trying to connect to API service.""" - pass - - -class AuthPluginOptionsMissing(AuthorizationFailure): - """Auth plugin misses some options.""" - def __init__(self, opt_names): - super(AuthPluginOptionsMissing, self).__init__( - _("Authentication failed. Missing options: %s") % - ", ".join(opt_names)) - self.opt_names = opt_names - - -class AuthSystemNotFound(AuthorizationFailure): - """User has specified an AuthSystem that is not installed.""" - def __init__(self, auth_system): - super(AuthSystemNotFound, self).__init__( - _("AuthSystemNotFound: %r") % auth_system) - self.auth_system = auth_system - - -class NoUniqueMatch(ClientException): - """Multiple entities found instead of one.""" - pass - - -class EndpointException(ClientException): - """Something is rotten in Service Catalog.""" - pass - - -class EndpointNotFound(EndpointException): - """Could not find requested endpoint in Service Catalog.""" - pass - - -class AmbiguousEndpoints(EndpointException): - """Found more than one matching endpoint in Service Catalog.""" - def __init__(self, endpoints=None): - super(AmbiguousEndpoints, self).__init__( - _("AmbiguousEndpoints: %r") % endpoints) - self.endpoints = endpoints - - -class HttpError(ClientException): - """The base exception class for all HTTP exceptions. - """ - http_status = 0 - message = _("HTTP Error") - - def __init__(self, message=None, details=None, - response=None, request_id=None, - url=None, method=None, http_status=None): - self.http_status = http_status or self.http_status - self.message = message or self.message - self.details = details - self.request_id = request_id - self.response = response - self.url = url - self.method = method - formatted_string = "%s (HTTP %s)" % (self.message, self.http_status) - if request_id: - formatted_string += " (Request-ID: %s)" % request_id - super(HttpError, self).__init__(formatted_string) - - -class HTTPRedirection(HttpError): - """HTTP Redirection.""" - message = _("HTTP Redirection") - - -class HTTPClientError(HttpError): - """Client-side HTTP error. - - Exception for cases in which the client seems to have erred. - """ - message = _("HTTP Client Error") - - -class HttpServerError(HttpError): - """Server-side HTTP error. - - Exception for cases in which the server is aware that it has - erred or is incapable of performing the request. - """ - message = _("HTTP Server Error") - - -class MultipleChoices(HTTPRedirection): - """HTTP 300 - Multiple Choices. - - Indicates multiple options for the resource that the client may follow. - """ - - http_status = 300 - message = _("Multiple Choices") - - -class BadRequest(HTTPClientError): - """HTTP 400 - Bad Request. - - The request cannot be fulfilled due to bad syntax. - """ - http_status = 400 - message = _("Bad Request") - - -class Unauthorized(HTTPClientError): - """HTTP 401 - Unauthorized. - - Similar to 403 Forbidden, but specifically for use when authentication - is required and has failed or has not yet been provided. - """ - http_status = 401 - message = _("Unauthorized") - - -class PaymentRequired(HTTPClientError): - """HTTP 402 - Payment Required. - - Reserved for future use. - """ - http_status = 402 - message = _("Payment Required") - - -class Forbidden(HTTPClientError): - """HTTP 403 - Forbidden. - - The request was a valid request, but the server is refusing to respond - to it. - """ - http_status = 403 - message = _("Forbidden") - - -class NotFound(HTTPClientError): - """HTTP 404 - Not Found. - - The requested resource could not be found but may be available again - in the future. - """ - http_status = 404 - message = _("Not Found") - - -class MethodNotAllowed(HTTPClientError): - """HTTP 405 - Method Not Allowed. - - A request was made of a resource using a request method not supported - by that resource. - """ - http_status = 405 - message = _("Method Not Allowed") - - -class NotAcceptable(HTTPClientError): - """HTTP 406 - Not Acceptable. - - The requested resource is only capable of generating content not - acceptable according to the Accept headers sent in the request. - """ - http_status = 406 - message = _("Not Acceptable") - - -class ProxyAuthenticationRequired(HTTPClientError): - """HTTP 407 - Proxy Authentication Required. - - The client must first authenticate itself with the proxy. - """ - http_status = 407 - message = _("Proxy Authentication Required") - - -class RequestTimeout(HTTPClientError): - """HTTP 408 - Request Timeout. - - The server timed out waiting for the request. - """ - http_status = 408 - message = _("Request Timeout") - - -class Conflict(HTTPClientError): - """HTTP 409 - Conflict. - - Indicates that the request could not be processed because of conflict - in the request, such as an edit conflict. - """ - http_status = 409 - message = _("Conflict") - - -class Gone(HTTPClientError): - """HTTP 410 - Gone. - - Indicates that the resource requested is no longer available and will - not be available again. - """ - http_status = 410 - message = _("Gone") - - -class LengthRequired(HTTPClientError): - """HTTP 411 - Length Required. - - The request did not specify the length of its content, which is - required by the requested resource. - """ - http_status = 411 - message = _("Length Required") - - -class PreconditionFailed(HTTPClientError): - """HTTP 412 - Precondition Failed. - - The server does not meet one of the preconditions that the requester - put on the request. - """ - http_status = 412 - message = _("Precondition Failed") - - -class RequestEntityTooLarge(HTTPClientError): - """HTTP 413 - Request Entity Too Large. - - The request is larger than the server is willing or able to process. - """ - http_status = 413 - message = _("Request Entity Too Large") - - def __init__(self, *args, **kwargs): - try: - self.retry_after = int(kwargs.pop('retry_after')) - except (KeyError, ValueError): - self.retry_after = 0 - - super(RequestEntityTooLarge, self).__init__(*args, **kwargs) - - -class RequestUriTooLong(HTTPClientError): - """HTTP 414 - Request-URI Too Long. - - The URI provided was too long for the server to process. - """ - http_status = 414 - message = _("Request-URI Too Long") - - -class UnsupportedMediaType(HTTPClientError): - """HTTP 415 - Unsupported Media Type. - - The request entity has a media type which the server or resource does - not support. - """ - http_status = 415 - message = _("Unsupported Media Type") - - -class RequestedRangeNotSatisfiable(HTTPClientError): - """HTTP 416 - Requested Range Not Satisfiable. - - The client has asked for a portion of the file, but the server cannot - supply that portion. - """ - http_status = 416 - message = _("Requested Range Not Satisfiable") - - -class ExpectationFailed(HTTPClientError): - """HTTP 417 - Expectation Failed. - - The server cannot meet the requirements of the Expect request-header field. - """ - http_status = 417 - message = _("Expectation Failed") - - -class UnprocessableEntity(HTTPClientError): - """HTTP 422 - Unprocessable Entity. - - The request was well-formed but was unable to be followed due to semantic - errors. - """ - http_status = 422 - message = _("Unprocessable Entity") - - -class InternalServerError(HttpServerError): - """HTTP 500 - Internal Server Error. - - A generic error message, given when no more specific message is suitable. - """ - http_status = 500 - message = _("Internal Server Error") - - -# NotImplemented is a python keyword. -class HttpNotImplemented(HttpServerError): - """HTTP 501 - Not Implemented. - - The server either does not recognize the request method, or it lacks - the ability to fulfill the request. - """ - http_status = 501 - message = _("Not Implemented") - - -class BadGateway(HttpServerError): - """HTTP 502 - Bad Gateway. - - The server was acting as a gateway or proxy and received an invalid - response from the upstream server. - """ - http_status = 502 - message = _("Bad Gateway") - - -class ServiceUnavailable(HttpServerError): - """HTTP 503 - Service Unavailable. - - The server is currently unavailable. - """ - http_status = 503 - message = _("Service Unavailable") - - -class GatewayTimeout(HttpServerError): - """HTTP 504 - Gateway Timeout. - - The server was acting as a gateway or proxy and did not receive a timely - response from the upstream server. - """ - http_status = 504 - message = _("Gateway Timeout") - - -class HttpVersionNotSupported(HttpServerError): - """HTTP 505 - HttpVersion Not Supported. - - The server does not support the HTTP protocol version used in the request. - """ - http_status = 505 - message = _("HTTP Version Not Supported") - - -# _code_map contains all the classes that have http_status attribute. -_code_map = dict( - (getattr(obj, 'http_status', None), obj) - for name, obj in six.iteritems(vars(sys.modules[__name__])) - if inspect.isclass(obj) and getattr(obj, 'http_status', False) -) - - -def from_response(response, method, url): - """Returns an instance of :class:`HttpError` or subclass based on response. - - :param response: instance of `requests.Response` class - :param method: HTTP method used for request - :param url: URL used for request - """ - - req_id = response.headers.get("x-openstack-request-id") - # NOTE(hdd) true for older versions of nova and cinder - if not req_id: - req_id = response.headers.get("x-compute-request-id") - kwargs = { - "http_status": response.status_code, - "response": response, - "method": method, - "url": url, - "request_id": req_id, - } - if "retry-after" in response.headers: - kwargs["retry_after"] = response.headers["retry-after"] - content_type = response.headers.get("Content-Type", "") - if content_type.startswith("application/json"): - try: - body = response.json() - except ValueError: - pass - else: - if isinstance(body, dict): - error = body.get(list(body)[0]) - if isinstance(error, dict): - kwargs["message"] = (error.get("message") or - error.get("faultstring")) - kwargs["details"] = (error.get("details") or - six.text_type(body)) - elif content_type.startswith("text/"): - kwargs["details"] = getattr(response, 'text', '') +"""Exception definitions.""" - try: - cls = _code_map[response.status_code] - except KeyError: - if 500 <= response.status_code < 600: - cls = HttpServerError - elif 400 <= response.status_code < 500: - cls = HTTPClientError - else: - cls = HttpError - return cls(**kwargs) +ClientException = exceptions.ClientException +ValidationError = exceptions.ValidationError +UnsupportedVersion = exceptions.UnsupportedVersion +CommandError = exceptions.CommandError +AuthorizationFailure = exceptions.AuthorizationFailure +ConnectionError = exceptions.ConnectionError +ConnectionRefused = exceptions.ConnectionRefused +AuthPluginOptionsMissing = exceptions.AuthPluginOptionsMissing +AuthSystemNotFound = exceptions.AuthSystemNotFound +NoUniqueMatch = exceptions.NoUniqueMatch +EndpointException = exceptions.EndpointException +EndpointNotFound = exceptions.EndpointNotFound +AmbiguousEndpoints = exceptions.AmbiguousEndpoints +HttpError = exceptions.HttpError +HTTPRedirection = exceptions.HTTPRedirection +HTTPClientError = exceptions.HTTPClientError +HttpServerError = exceptions.HttpServerError +MultipleChoices = exceptions.MultipleChoices +BadRequest = exceptions.BadRequest +Unauthorized = exceptions.Unauthorized +PaymentRequired = exceptions.PaymentRequired +Forbidden = exceptions.Forbidden +NotFound = exceptions.NotFound +MethodNotAllowed = exceptions.MethodNotAllowed +NotAcceptable = exceptions.NotAcceptable +ProxyAuthenticationRequired = exceptions.ProxyAuthenticationRequired +RequestTimeout = exceptions.RequestTimeout +Conflict = exceptions.Conflict +Gone = exceptions.Gone +LengthRequired = exceptions.LengthRequired +PreconditionFailed = exceptions.PreconditionFailed +RequestEntityTooLarge = exceptions.RequestEntityTooLarge +RequestUriTooLong = exceptions.RequestUriTooLong +UnsupportedMediaType = exceptions.UnsupportedMediaType +RequestedRangeNotSatisfiable = exceptions.RequestedRangeNotSatisfiable +ExpectationFailed = exceptions.ExpectationFailed +UnprocessableEntity = exceptions.UnprocessableEntity +InternalServerError = exceptions.InternalServerError +HttpNotImplemented = exceptions.HttpNotImplemented +BadGateway = exceptions.BadGateway +ServiceUnavailable = exceptions.ServiceUnavailable +GatewayTimeout = exceptions.GatewayTimeout +HttpVersionNotSupported = exceptions.HttpVersionNotSupported +from_response = exceptions.from_response diff -Nru python-keystoneclient-1.6.0/keystoneclient/openstack/common/apiclient/__init__.py python-keystoneclient-1.7.1/keystoneclient/openstack/common/apiclient/__init__.py --- python-keystoneclient-1.6.0/keystoneclient/openstack/common/apiclient/__init__.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/openstack/common/apiclient/__init__.py 2015-09-09 04:34:24.000000000 +0000 @@ -0,0 +1,22 @@ + +# 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. + + +from debtcollector import removals + + +removals.removed_module('keystoneclient.openstack.common.apiclient', + version='0.7.1', + removal_version='2.0') diff -Nru python-keystoneclient-1.6.0/keystoneclient/service_catalog.py python-keystoneclient-1.7.1/keystoneclient/service_catalog.py --- python-keystoneclient-1.6.0/keystoneclient/service_catalog.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/service_catalog.py 2015-09-09 04:34:24.000000000 +0000 @@ -17,6 +17,7 @@ # limitations under the License. import abc +import warnings import six @@ -27,11 +28,27 @@ @six.add_metaclass(abc.ABCMeta) class ServiceCatalog(object): - """Helper methods for dealing with a Keystone Service Catalog.""" + """Helper methods for dealing with a Keystone Service Catalog. + + .. warning:: + + Setting region_name is deprecated in favor of passing the region name + as a parameter to calls made to the service catalog as of the 1.7.0 + release and may be removed in the 2.0.0 release. + + """ @classmethod def factory(cls, resource_dict, token=None, region_name=None): - """Create ServiceCatalog object given an auth token.""" + """Create ServiceCatalog object given an auth token. + + .. warning:: + + Setting region_name is deprecated in favor of passing the region + name as a parameter to calls made to the service catalog as of the + 1.7.0 release and may be removed in the 2.0.0 release. + + """ if ServiceCatalogV3.is_valid(resource_dict): return ServiceCatalogV3(token, resource_dict, region_name) elif ServiceCatalogV2.is_valid(resource_dict): @@ -40,13 +57,32 @@ raise NotImplementedError(_('Unrecognized auth response')) def __init__(self, region_name=None): + if region_name: + warnings.warn( + 'Setting region_name on the service catalog is deprecated in ' + 'favor of passing the region name as a parameter to calls ' + 'made to the service catalog as of the 1.7.0 release and may ' + 'be removed in the 2.0.0 release.', + DeprecationWarning) + self._region_name = region_name @property def region_name(self): - # FIXME(jamielennox): Having region_name set on the service catalog - # directly is deprecated. It should instead be provided as a parameter - # to calls made to the service_catalog. Provide appropriate warning. + """Region name. + + .. warning:: + + region_name is deprecated in favor of passing the region name as a + parameter to calls made to the service catalog as of the 1.7.0 + release and may be removed in the 2.0.0 release. + + """ + warnings.warn( + 'region_name is deprecated in favor of passing the region name as ' + 'a parameter to calls made to the service catalog as of the 1.7.0 ' + 'release and may be removed in the 2.0.0 release.', + DeprecationWarning) return self._region_name def _get_endpoint_region(self, endpoint): @@ -155,10 +191,13 @@ except KeyError: return - # TODO(jamielennox): at least swiftclient is known to set attr and not - # filter_value and expects that to mean that filtering is ignored, so - # we can't check for the presence of attr. This behaviour should be - # deprecated and an appropriate warning provided. + if attr and not filter_value: + warnings.warn( + 'Providing attr without filter_value to get_urls() is ' + 'deprecated as of the 1.7.0 release and may be removed in the ' + '2.0.0 release. Either both should be provided or neither ' + 'should be provided.') + if filter_value: return [endpoint for endpoint in endpoints if endpoint.get(attr) == filter_value] diff -Nru python-keystoneclient-1.6.0/keystoneclient/session.py python-keystoneclient-1.7.1/keystoneclient/session.py --- python-keystoneclient-1.6.0/keystoneclient/session.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/session.py 2015-09-09 04:34:24.000000000 +0000 @@ -17,10 +17,13 @@ import os import socket import time +import warnings +from debtcollector import removals from oslo_config import cfg from oslo_serialization import jsonutils from oslo_utils import importutils +from oslo_utils import strutils import requests import six from six.moves import urllib @@ -116,12 +119,14 @@ _REDIRECT_STATUSES = (301, 302, 303, 305, 307) REDIRECT_STATUSES = _REDIRECT_STATUSES - """This property is deprecated.""" + """This property is deprecated as of the 1.7.0 release and may be removed + in the 2.0.0 release.""" _DEFAULT_REDIRECT_LIMIT = 30 DEFAULT_REDIRECT_LIMIT = _DEFAULT_REDIRECT_LIMIT - """This property is deprecated.""" + """This property is deprecated as of the 1.7.0 release and may be removed + in the 2.0.0 release.""" @utils.positional(2, enforcement=utils.positional.WARN) def __init__(self, auth=None, session=None, original_ip=None, verify=True, @@ -130,7 +135,7 @@ if not session: session = requests.Session() # Use TCPKeepAliveAdapter to fix bug 1323862 - for scheme in session.adapters.keys(): + for scheme in session.adapters: session.mount(scheme, TCPKeepAliveAdapter()) self.auth = auth @@ -162,7 +167,7 @@ @utils.positional() def _http_log_request(self, url, method=None, data=None, - json=None, headers=None, logger=_logger): + headers=None, logger=_logger): if not logger.isEnabledFor(logging.DEBUG): # NOTE(morganfainberg): This whole debug section is expensive, # there is no need to do the work if we're not going to emit a @@ -187,39 +192,25 @@ for header in six.iteritems(headers): string_parts.append('-H "%s: %s"' % self._process_header(header)) - if json: - data = jsonutils.dumps(json) if data: string_parts.append("-d '%s'" % data) logger.debug(' '.join(string_parts)) - @utils.positional() - def _http_log_response(self, response=None, json=None, - status_code=None, headers=None, text=None, - logger=_logger): + def _http_log_response(self, response, logger): if not logger.isEnabledFor(logging.DEBUG): return - if response is not None: - if not status_code: - status_code = response.status_code - if not headers: - headers = response.headers - if not text: - text = _remove_service_catalog(response.text) - if json: - text = jsonutils.dumps(json) + text = _remove_service_catalog(response.text) string_parts = ['RESP:'] - if status_code: - string_parts.append('[%s]' % status_code) - if headers: - for header in six.iteritems(headers): - string_parts.append('%s: %s' % self._process_header(header)) + string_parts.append('[%s]' % response.status_code) + for header in six.iteritems(response.headers): + string_parts.append('%s: %s' % self._process_header(header)) if text: - string_parts.append('\nRESP BODY: %s\n' % text) + string_parts.append('\nRESP BODY: %s\n' % + strutils.mask_password(text)) logger.debug(' '.join(string_parts)) @@ -379,6 +370,19 @@ send = functools.partial(self._send_request, url, method, redirect, log, logger, connect_retries) + + try: + connection_params = self.get_auth_connection_params(auth=auth) + except exceptions.MissingAuthPlugin: + # NOTE(jamielennox): If we've gotten this far without an auth + # plugin then we should be happy with allowing no additional + # connection params. This will be the typical case for plugins + # anyway. + pass + else: + if connection_params: + kwargs.update(connection_params) + resp = send(**kwargs) # handle getting a 401 Unauthorized response by invalidating the plugin @@ -439,7 +443,7 @@ **kwargs) if log: - self._http_log_response(response=resp, logger=logger) + self._http_log_response(resp, logger) if resp.status_code in self._REDIRECT_STATUSES: # be careful here in python True == 1 and False == 0 @@ -455,8 +459,8 @@ try: location = resp.headers['location'] except KeyError: - logger.warn(_LW("Failed to redirect request to %s as new " - "location was not provided."), resp.url) + logger.warning(_LW("Failed to redirect request to %s as new " + "location was not provided."), resp.url) else: # NOTE(jamielennox): We don't pass through connect_retry_delay. # This request actually worked so we can reset the delay count. @@ -527,15 +531,27 @@ new request-style arguments. .. warning:: - *DEPRECATED*: This function is purely for bridging the gap between - older client arguments and the session arguments that they relate - to. It is not intended to be used as a generic Session Factory. + + *DEPRECATED as of 1.7.0*: This function is purely for bridging the + gap between older client arguments and the session arguments that + they relate to. It is not intended to be used as a generic Session + Factory. This function may be removed in the 2.0.0 release. This function purposefully modifies the input kwargs dictionary so that the remaining kwargs dict can be reused and passed on to other functions without session arguments. """ + + warnings.warn( + 'Session.construct() is deprecated as of the 1.7.0 release in ' + 'favor of using session constructor and may be removed in the ' + '2.0.0 release.', DeprecationWarning) + + return cls._construct(kwargs) + + @classmethod + def _construct(cls, kwargs): params = {} for attr in ('verify', 'cacert', 'cert', 'key', 'insecure', @@ -563,8 +579,11 @@ verify = cacert or True if cert and key: - # passing cert and key together is deprecated in favour of the - # requests lib form of having the cert and key as a tuple + warnings.warn( + 'Passing cert and key together is deprecated as of the 1.7.0 ' + 'release in favor of the requests library form of having the ' + 'cert and key as a tuple and may be removed in the 2.0.0 ' + 'release.', DeprecationWarning) cert = (cert, key) return cls(verify=verify, cert=cert, **kwargs) @@ -597,6 +616,8 @@ auth = self._auth_required(auth, msg) return auth.get_headers(self, **kwargs) + @removals.remove(message='Use get_auth_headers instead.', version='1.7.0', + removal_version='2.0.0') def get_token(self, auth=None): """Return a token as provided by the auth plugin. @@ -609,9 +630,12 @@ :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not available. - *DEPRECATED*: This assumes that the only header that is used to - authenticate a message is 'X-Auth-Token'. This may not be - correct. Use get_auth_headers instead. + .. warning:: + + This method is deprecated as of the 1.7.0 release in favor of + :meth:`get_auth_headers` and may be removed in the 2.0.0 release. + This method assumes that the only header that is used to + authenticate a message is 'X-Auth-Token' which may not be correct. :returns: A valid token. :rtype: string @@ -635,6 +659,59 @@ auth = self._auth_required(auth, msg) return auth.get_endpoint(self, **kwargs) + def get_auth_connection_params(self, auth=None, **kwargs): + """Return auth connection params as provided by the auth plugin. + + An auth plugin may specify connection parameters to the request like + providing a client certificate for communication. + + We restrict the values that may be returned from this function to + prevent an auth plugin overriding values unrelated to connection + parmeters. The values that are currently accepted are: + + - `cert`: a path to a client certificate, or tuple of client + certificate and key pair that are used with this request. + - `verify`: a boolean value to indicate verifying SSL certificates + against the system CAs or a path to a CA file to verify with. + + These values are passed to the requests library and further information + on accepted values may be found there. + + :param auth: The auth plugin to use for tokens. Overrides the plugin + on the session. (optional) + :type auth: keystoneclient.auth.base.BaseAuthPlugin + + :raises keystoneclient.exceptions.AuthorizationFailure: if a new token + fetch fails. + :raises keystoneclient.exceptions.MissingAuthPlugin: if a plugin is not + available. + :raises keystoneclient.exceptions.UnsupportedParameters: if the plugin + returns a parameter that is not supported by this session. + + :returns: Authentication headers or None for failure. + :rtype: dict + """ + msg = _('An auth plugin is required to fetch connection params') + auth = self._auth_required(auth, msg) + params = auth.get_connection_params(self, **kwargs) + + # NOTE(jamielennox): There needs to be some consensus on what + # parameters are allowed to be modified by the auth plugin here. + # Ideally I think it would be only the send() parts of the request + # flow. For now lets just allow certain elements. + params_copy = params.copy() + + for arg in ('cert', 'verify'): + try: + kwargs[arg] = params_copy.pop(arg) + except KeyError: + pass + + if params_copy: + raise exceptions.UnsupportedParameters(list(params_copy)) + + return params + def invalidate(self, auth=None): """Invalidate an authentication plugin. @@ -782,8 +859,8 @@ kwargs['insecure'] = c.insecure kwargs['cacert'] = c.cafile - kwargs['cert'] = c.certfile - kwargs['key'] = c.keyfile + if c.certfile and c.keyfile: + kwargs['cert'] = (c.certfile, c.keyfile) kwargs['timeout'] = c.timeout return cls._make(**kwargs) @@ -840,19 +917,58 @@ """ kwargs['insecure'] = args.insecure kwargs['cacert'] = args.os_cacert - kwargs['cert'] = args.os_cert - kwargs['key'] = args.os_key + if args.os_cert and args.os_key: + kwargs['cert'] = (args.os_cert, args.os_key) kwargs['timeout'] = args.timeout return cls._make(**kwargs) class TCPKeepAliveAdapter(requests.adapters.HTTPAdapter): - """The custom adapter used to set TCP Keep-Alive on all connections.""" + """The custom adapter used to set TCP Keep-Alive on all connections. + + This Adapter also preserves the default behaviour of Requests which + disables Nagle's Algorithm. See also: + http://blogs.msdn.com/b/windowsazurestorage/archive/2010/06/25/nagle-s-algorithm-is-not-friendly-towards-small-requests.aspx + """ def init_poolmanager(self, *args, **kwargs): - if requests.__version__ >= '2.4.1': - kwargs.setdefault('socket_options', [ + if 'socket_options' not in kwargs: + socket_options = [ + # Keep Nagle's algorithm off (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1), + # Turn on TCP Keep-Alive (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), - ]) + ] + + # Some operating systems (e.g., OSX) do not support setting + # keepidle + if hasattr(socket, 'TCP_KEEPIDLE'): + socket_options += [ + # Wait 60 seconds before sending keep-alive probes + (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60) + ] + + # TODO(claudiub): Windows does not contain the TCP_KEEPCNT and + # TCP_KEEPINTVL socket attributes. Instead, it contains + # SIO_KEEPALIVE_VALS, which can be set via ioctl, which should be + # set once it is available in requests. + # https://msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx + if hasattr(socket, 'TCP_KEEPCNT'): + socket_options += [ + # Set the maximum number of keep-alive probes + (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4) + ] + + if hasattr(socket, 'TCP_KEEPINTVL'): + socket_options += [ + # Send keep-alive probes every 15 seconds + (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15) + ] + + # After waiting 60 seconds, and then sending a probe once every 15 + # seconds 4 times, these options should ensure that a connection + # hands for no longer than 2 minutes before a ConnectionError is + # raised. + + kwargs['socket_options'] = socket_options super(TCPKeepAliveAdapter, self).init_poolmanager(*args, **kwargs) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/functional/hooks/post_test_hook.sh python-keystoneclient-1.7.1/keystoneclient/tests/functional/hooks/post_test_hook.sh --- python-keystoneclient-1.6.0/keystoneclient/tests/functional/hooks/post_test_hook.sh 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/functional/hooks/post_test_hook.sh 2015-09-09 04:34:24.000000000 +0000 @@ -18,7 +18,7 @@ if [ -f .testrepository/0 ]; then sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit - sudo .tox/functional/bin/python /usr/local/jenkins/slave_scripts/subunit2html.py $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html + sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html sudo gzip -9 $BASE/logs/testrepository.subunit sudo gzip -9 $BASE/logs/testr_results.html sudo chown jenkins:jenkins $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/functional/test_cli.py python-keystoneclient-1.7.1/keystoneclient/tests/functional/test_cli.py --- python-keystoneclient-1.6.0/keystoneclient/tests/functional/test_cli.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/functional/test_cli.py 2015-09-09 04:34:24.000000000 +0000 @@ -59,8 +59,8 @@ # check that region and publicURL exists. One might also # check for adminURL and internalURL. id seems to be optional # and is missing in the catalog backend - self.assertIn('publicURL', svc.keys()) - self.assertIn('region', svc.keys()) + self.assertIn('publicURL', svc) + self.assertIn('region', svc) def test_admin_endpoint_list(self): out = self.keystone('endpoint-list') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_common.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_common.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_common.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_common.py 2015-09-09 04:34:24.000000000 +0000 @@ -14,12 +14,14 @@ import datetime import uuid +import mock from oslo_utils import timeutils import six from keystoneclient import access from keystoneclient.auth import base from keystoneclient.auth import identity +from keystoneclient import exceptions from keystoneclient import fixture from keystoneclient import session from keystoneclient.tests.unit import utils @@ -411,6 +413,9 @@ self.headers = {'headerA': 'valueA', 'headerB': 'valueB'} + self.cert = '/path/to/cert' + self.connection_params = {'cert': self.cert, 'verify': False} + def url(self, prefix): return '%s/%s' % (self.endpoint, prefix) @@ -424,6 +429,9 @@ def get_endpoint(self, session, **kwargs): return self.endpoint + def get_connection_params(self, session, **kwargs): + return self.connection_params + class GenericAuthPluginTests(utils.TestCase): @@ -446,8 +454,43 @@ for k, v in six.iteritems(self.auth.headers): self.assertRequestHeaderEqual(k, v) - self.assertIsNone(self.session.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertIsNone(self.session.get_token()) self.assertEqual(self.auth.headers, self.session.get_auth_headers()) self.assertNotIn('X-Auth-Token', self.requests_mock.last_request.headers) + + def test_setting_connection_params(self): + text = uuid.uuid4().hex + + with mock.patch.object(self.session.session, 'request') as mocked: + mocked.return_value = utils.TestResponse({'status_code': 200, + 'text': text}) + resp = self.session.get('prefix', + endpoint_filter=self.ENDPOINT_FILTER) + + self.assertEqual(text, resp.text) + + # the cert and verify values passed to request are those that were + # returned from the auth plugin as connection params. + + mocked.assert_called_once_with('GET', + self.auth.url('prefix'), + headers=mock.ANY, + allow_redirects=False, + cert=self.auth.cert, + verify=False) + + def test_setting_bad_connection_params(self): + # The uuid name parameter here is unknown and not in the allowed params + # to be returned to the session and so an error will be raised. + name = uuid.uuid4().hex + self.auth.connection_params[name] = uuid.uuid4().hex + + e = self.assertRaises(exceptions.UnsupportedParameters, + self.session.get, + 'prefix', + endpoint_filter=self.ENDPOINT_FILTER) + + self.assertIn(name, str(e)) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_v2.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_v2.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_v2.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_v2.py 2015-09-09 04:34:24.000000000 +0000 @@ -275,11 +275,13 @@ password=self.TEST_PASS) s = session.Session(auth=a) - self.assertEqual('token1', s.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual('token1', s.get_token()) self.assertEqual({'X-Auth-Token': 'token1'}, s.get_auth_headers()) a.invalidate() - self.assertEqual('token2', s.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual('token2', s.get_token()) self.assertEqual({'X-Auth-Token': 'token2'}, s.get_auth_headers()) def test_doesnt_log_password(self): @@ -289,7 +291,8 @@ a = v2.Password(self.TEST_URL, username=self.TEST_USER, password=password) s = session.Session(auth=a) - self.assertEqual(self.TEST_TOKEN, s.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(self.TEST_TOKEN, s.get_token()) self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, s.get_auth_headers()) self.assertNotIn(password, self.logger.output) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_v3_federated.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_v3_federated.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_v3_federated.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_v3_federated.py 2015-09-09 04:34:24.000000000 +0000 @@ -76,7 +76,8 @@ def test_unscoped_behaviour(self): sess = session.Session(auth=self.get_plugin()) - self.assertEqual(self.unscoped_token_id, sess.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(self.unscoped_token_id, sess.get_token()) self.assertTrue(self.unscoped_mock.called) self.assertFalse(self.scoped_mock.called) @@ -84,7 +85,8 @@ def test_scoped_behaviour(self): auth = self.get_plugin(project_id=self.scoped_token.project_id) sess = session.Session(auth=auth) - self.assertEqual(self.scoped_token_id, sess.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(self.scoped_token_id, sess.get_token()) self.assertTrue(self.unscoped_mock.called) self.assertTrue(self.scoped_mock.called) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_v3.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_v3.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/auth/test_identity_v3.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/auth/test_identity_v3.py 2015-09-09 04:34:24.000000000 +0000 @@ -245,7 +245,7 @@ self.stub_auth(json=self.TEST_RESPONSE_DICT) a = v3.Password(self.TEST_URL, username=self.TEST_USER, password=self.TEST_PASS, - project_id=self.TEST_DOMAIN_ID) + project_id=self.TEST_TENANT_ID) s = session.Session(a) self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, @@ -255,10 +255,10 @@ {'methods': ['password'], 'password': {'user': {'name': self.TEST_USER, 'password': self.TEST_PASS}}}, - 'scope': {'project': {'id': self.TEST_DOMAIN_ID}}}} + 'scope': {'project': {'id': self.TEST_TENANT_ID}}}} self.assertRequestBodyIs(json=req) self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN) - self.assertEqual(s.auth.auth_ref.project_id, self.TEST_DOMAIN_ID) + self.assertEqual(s.auth.auth_ref.project_id, self.TEST_TENANT_ID) def test_authenticate_with_token(self): self.stub_auth(json=self.TEST_RESPONSE_DICT) @@ -458,10 +458,12 @@ password=self.TEST_PASS) s = session.Session(auth=a) - self.assertEqual('token1', s.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual('token1', s.get_token()) self.assertEqual({'X-Auth-Token': 'token1'}, s.get_auth_headers()) a.invalidate() - self.assertEqual('token2', s.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual('token2', s.get_token()) self.assertEqual({'X-Auth-Token': 'token2'}, s.get_auth_headers()) def test_doesnt_log_password(self): @@ -471,7 +473,8 @@ a = v3.Password(self.TEST_URL, username=self.TEST_USER, password=password) s = session.Session(a) - self.assertEqual(self.TEST_TOKEN, s.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(self.TEST_TOKEN, s.get_token()) self.assertEqual({'X-Auth-Token': self.TEST_TOKEN}, s.get_auth_headers()) @@ -487,7 +490,7 @@ include_catalog=False) s = session.Session(auth=a) - s.get_token() + s.get_auth_headers() auth_url = self.TEST_URL + '/auth/tokens' self.assertEqual(auth_url, a.token_url) @@ -512,7 +515,8 @@ auth_ref = a.get_access(s) - self.assertFalse(auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertFalse(auth_ref.scoped) body = self.requests_mock.last_request.json() ident = body['auth']['identity'] diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/client_fixtures.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/client_fixtures.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/client_fixtures.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/client_fixtures.py 2015-09-09 04:34:24.000000000 +0000 @@ -12,7 +12,9 @@ # License for the specific language governing permissions and limitations # under the License. +import contextlib import os +import warnings import fixtures from oslo_serialization import jsonutils @@ -595,3 +597,25 @@ (30, 0, 'K333'), ], } + + +class Deprecations(fixtures.Fixture): + def setUp(self): + super(Deprecations, self).setUp() + + # If keystoneclient calls any deprecated function this will raise an + # exception. + warnings.filterwarnings('error', category=DeprecationWarning, + module='^keystoneclient\\.') + self.addCleanup(warnings.resetwarnings) + + def expect_deprecations(self): + """Call this if the test expects to call deprecated function.""" + warnings.resetwarnings() + + @contextlib.contextmanager + def expect_deprecations_here(self): + warnings.resetwarnings() + yield + warnings.filterwarnings('error', category=DeprecationWarning, + module='^keystoneclient\\.') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/generic/test_client.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/generic/test_client.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/generic/test_client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/generic/test_client.py 2015-09-09 04:34:24.000000000 +0000 @@ -57,7 +57,9 @@ def test_discover_extensions_v2(self): self.requests_mock.get("%s/extensions" % V2_URL, text=EXTENSION_LIST) - extensions = client.Client().discover_extensions(url=V2_URL) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + extensions = client.Client().discover_extensions(url=V2_URL) self.assertIn(EXTENSION_ALIAS_FOO, extensions) self.assertEqual(extensions[EXTENSION_ALIAS_FOO], EXTENSION_NAME_FOO) self.assertIn(EXTENSION_ALIAS_BAR, extensions) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_auth_token_middleware.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_auth_token_middleware.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_auth_token_middleware.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_auth_token_middleware.py 2015-09-09 04:34:24.000000000 +0000 @@ -43,6 +43,7 @@ from keystoneclient.openstack.common import memorycache from keystoneclient.tests.unit import client_fixtures from keystoneclient.tests.unit import utils +from keystoneclient import utils as client_utils EXPECTED_V2_DEFAULT_ENV_RESPONSE = { @@ -205,7 +206,9 @@ """ def setUp(self, expected_env=None, auth_version=None, fake_app=None): - testtools.TestCase.setUp(self) + super(BaseAuthTokenMiddlewareTest, self).setUp() + + self.useFixture(client_fixtures.Deprecations()) self.expected_env = expected_env or dict() self.fake_app = fake_app or FakeApp @@ -452,7 +455,7 @@ self.set_middleware(conf=conf) token = b'my_token' some_time_later = timeutils.utcnow() + datetime.timedelta(hours=4) - expires = timeutils.strtime(some_time_later) + expires = client_utils.strtime(some_time_later) data = ('this_data', expires) token_cache = self.middleware._token_cache token_cache.initialize({}) @@ -469,7 +472,7 @@ self.set_middleware(conf=conf) token = b'my_token' some_time_later = timeutils.utcnow() + datetime.timedelta(hours=4) - expires = timeutils.strtime(some_time_later) + expires = client_utils.strtime(some_time_later) data = ('this_data', expires) token_cache = self.middleware._token_cache token_cache.initialize({}) @@ -485,7 +488,7 @@ self.set_middleware(conf=conf) token = 'my_token' some_time_later = timeutils.utcnow() + datetime.timedelta(hours=4) - expires = timeutils.strtime(some_time_later) + expires = client_utils.strtime(some_time_later) data = ('this_data', expires) token_cache = self.middleware._token_cache token_cache.initialize({}) @@ -927,7 +930,7 @@ self.msg = None self.debugmsg = None - def warn(self, msg=None, *args, **kwargs): + def warning(self, msg=None, *args, **kwargs): self.msg = msg def debug(self, msg=None, *args, **kwargs): @@ -1672,6 +1675,10 @@ class TokenEncodingTest(testtools.TestCase): + def setUp(self): + super(TokenEncodingTest, self).setUp() + self.useFixture(client_fixtures.Deprecations()) + def test_unquoted_token(self): self.assertEqual('foo%20bar', auth_token.safe_quote('foo bar')) @@ -1684,10 +1691,10 @@ super(TokenExpirationTest, self).setUp() self.now = timeutils.utcnow() self.delta = datetime.timedelta(hours=1) - self.one_hour_ago = timeutils.isotime(self.now - self.delta, - subsecond=True) - self.one_hour_earlier = timeutils.isotime(self.now + self.delta, - subsecond=True) + self.one_hour_ago = client_utils.isotime(self.now - self.delta, + subsecond=True) + self.one_hour_earlier = client_utils.isotime(self.now + self.delta, + subsecond=True) def create_v2_token_fixture(self, expires=None): v2_fixture = { @@ -1820,7 +1827,7 @@ data = 'this_data' self.set_middleware() self.middleware._token_cache.initialize({}) - some_time_later = timeutils.strtime(at=(self.now + self.delta)) + some_time_later = client_utils.strtime(at=(self.now + self.delta)) expires = some_time_later self.middleware._token_cache.store(token, data, expires) self.assertEqual(self.middleware._token_cache._cache_get(token), data) @@ -1848,7 +1855,7 @@ data = 'this_data' self.set_middleware() self.middleware._token_cache.initialize({}) - some_time_earlier = timeutils.strtime(at=(self.now - self.delta)) + some_time_earlier = client_utils.strtime(at=(self.now - self.delta)) expires = some_time_earlier self.middleware._token_cache.store(token, data, expires) self.assertThat(lambda: self.middleware._token_cache._cache_get(token), @@ -1861,7 +1868,7 @@ self.middleware._token_cache.initialize({}) timezone_offset = datetime.timedelta(hours=2) some_time_later = self.now - timezone_offset + self.delta - expires = timeutils.strtime(some_time_later) + '-02:00' + expires = client_utils.strtime(some_time_later) + '-02:00' self.middleware._token_cache.store(token, data, expires) self.assertEqual(self.middleware._token_cache._cache_get(token), data) @@ -1872,7 +1879,7 @@ self.middleware._token_cache.initialize({}) timezone_offset = datetime.timedelta(hours=2) some_time_earlier = self.now - timezone_offset - self.delta - expires = timeutils.strtime(some_time_earlier) + '-02:00' + expires = client_utils.strtime(some_time_earlier) + '-02:00' self.middleware._token_cache.store(token, data, expires) self.assertThat(lambda: self.middleware._token_cache._cache_get(token), matchers.raises(auth_token.InvalidUserToken)) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_base.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_base.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_base.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_base.py 2015-09-09 04:34:24.000000000 +0000 @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +from oslotest import mockpatch + from keystoneclient import base from keystoneclient.tests.unit import utils from keystoneclient.v2_0 import client @@ -34,15 +36,15 @@ self.assertEqual(base.getid(TmpObject), 4) def test_resource_lazy_getattr(self): - self.client = client.Client(username=self.TEST_USER, - token=self.TEST_TOKEN, - tenant_name=self.TEST_TENANT_NAME, - auth_url='http://127.0.0.1:5000', - endpoint='http://127.0.0.1:5000') - - self.client._adapter.get = self.mox.CreateMockAnything() - self.client._adapter.get('/OS-KSADM/roles/1').AndRaise(AttributeError) - self.mox.ReplayAll() + # Creating a Client not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + self.client = client.Client(token=self.TEST_TOKEN, + auth_url='http://127.0.0.1:5000', + endpoint='http://127.0.0.1:5000') + + self.useFixture(mockpatch.PatchObject( + self.client._adapter, 'get', side_effect=AttributeError, + autospec=True)) f = roles.Role(self.client.roles, {'id': 1, 'name': 'Member'}) self.assertEqual(f.name, 'Member') @@ -83,79 +85,93 @@ def setUp(self): super(ManagerTest, self).setUp() - self.client = client.Client(username=self.TEST_USER, - token=self.TEST_TOKEN, - tenant_name=self.TEST_TENANT_NAME, - auth_url='http://127.0.0.1:5000', - endpoint='http://127.0.0.1:5000') + + # Creating a Client not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + self.client = client.Client(token=self.TEST_TOKEN, + auth_url='http://127.0.0.1:5000', + endpoint='http://127.0.0.1:5000') + self.mgr = base.Manager(self.client) self.mgr.resource_class = base.Resource def test_api(self): - self.assertEqual(self.mgr.api, self.client) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(self.mgr.api, self.client) def test_get(self): - self.client.get = self.mox.CreateMockAnything() - self.client.get(self.url).AndReturn((None, self.body)) - self.mox.ReplayAll() - + get_mock = self.useFixture(mockpatch.PatchObject( + self.client, 'get', autospec=True, return_value=(None, self.body)) + ).mock rsrc = self.mgr._get(self.url, "hello") + get_mock.assert_called_once_with(self.url) self.assertEqual(rsrc.hi, 1) def test_post(self): - self.client.post = self.mox.CreateMockAnything() - self.client.post(self.url, body=self.body).AndReturn((None, self.body)) - self.client.post(self.url, body=self.body).AndReturn((None, self.body)) - self.mox.ReplayAll() + post_mock = self.useFixture(mockpatch.PatchObject( + self.client, 'post', autospec=True, return_value=(None, self.body)) + ).mock rsrc = self.mgr._post(self.url, self.body, "hello") + post_mock.assert_called_once_with(self.url, body=self.body) self.assertEqual(rsrc.hi, 1) + post_mock.reset_mock() + rsrc = self.mgr._post(self.url, self.body, "hello", return_raw=True) + post_mock.assert_called_once_with(self.url, body=self.body) self.assertEqual(rsrc["hi"], 1) def test_put(self): - self.client.put = self.mox.CreateMockAnything() - self.client.put(self.url, body=self.body).AndReturn((None, self.body)) - self.client.put(self.url, body=self.body).AndReturn((None, self.body)) - self.mox.ReplayAll() + put_mock = self.useFixture(mockpatch.PatchObject( + self.client, 'put', autospec=True, return_value=(None, self.body)) + ).mock rsrc = self.mgr._put(self.url, self.body, "hello") + put_mock.assert_called_once_with(self.url, body=self.body) self.assertEqual(rsrc.hi, 1) + put_mock.reset_mock() + rsrc = self.mgr._put(self.url, self.body) + put_mock.assert_called_once_with(self.url, body=self.body) self.assertEqual(rsrc.hello["hi"], 1) def test_patch(self): - self.client.patch = self.mox.CreateMockAnything() - self.client.patch(self.url, body=self.body).AndReturn( - (None, self.body)) - self.client.patch(self.url, body=self.body).AndReturn( - (None, self.body)) - self.mox.ReplayAll() + patch_mock = self.useFixture(mockpatch.PatchObject( + self.client, 'patch', autospec=True, + return_value=(None, self.body)) + ).mock rsrc = self.mgr._patch(self.url, self.body, "hello") + patch_mock.assert_called_once_with(self.url, body=self.body) self.assertEqual(rsrc.hi, 1) + patch_mock.reset_mock() + rsrc = self.mgr._patch(self.url, self.body) + patch_mock.assert_called_once_with(self.url, body=self.body) self.assertEqual(rsrc.hello["hi"], 1) def test_update(self): - self.client.patch = self.mox.CreateMockAnything() - self.client.put = self.mox.CreateMockAnything() - self.client.patch( - self.url, body=self.body, management=False).AndReturn((None, - self.body)) - self.client.put(self.url, body=None, management=True).AndReturn( - (None, self.body)) - self.mox.ReplayAll() + patch_mock = self.useFixture(mockpatch.PatchObject( + self.client, 'patch', autospec=True, + return_value=(None, self.body)) + ).mock + + put_mock = self.useFixture(mockpatch.PatchObject( + self.client, 'put', autospec=True, return_value=(None, self.body)) + ).mock rsrc = self.mgr._update( self.url, body=self.body, response_key="hello", method="PATCH", management=False) + patch_mock.assert_called_once_with( + self.url, management=False, body=self.body) self.assertEqual(rsrc.hi, 1) rsrc = self.mgr._update( self.url, body=None, response_key="hello", method="PUT", management=True) + put_mock.assert_called_once_with(self.url, management=True, body=None) self.assertEqual(rsrc.hi, 1) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_discovery.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_discovery.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_discovery.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_discovery.py 2015-09-09 04:34:24.000000000 +0000 @@ -472,7 +472,8 @@ cl = self.assertCreatesV2(auth_url=BASE_URL, **kwargs) - self.assertEqual(cl.original_ip, '100') + with self.deprecations.expect_deprecations_here(): + self.assertEqual(cl.original_ip, '100') self.assertEqual(cl.stale_duration, 15) self.assertFalse(cl.use_keyring) @@ -483,8 +484,10 @@ text=V3_AUTH_RESPONSE, headers={'X-Subject-Token': V3_TOKEN}) - disc = discover.Discover(auth_url=BASE_URL, debug=False, - username='foo') + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL, debug=False, + username='foo') client = disc.create_client(debug=True, password='bar') self.assertIsInstance(client, v3_client.Client) @@ -497,9 +500,12 @@ self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_ENTRY) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) - versions = disc.available_versions() + with self.deprecations.expect_deprecations_here(): + versions = disc.available_versions() self.assertEqual(1, len(versions)) self.assertEqual(V3_VERSION, versions[0]) @@ -513,7 +519,9 @@ versions.add_version(V4_VERSION) self.requests_mock.get(BASE_URL, status_code=300, json=versions) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) self.assertRaises(exceptions.DiscoveryFailure, disc.create_client, version=4) @@ -521,7 +529,9 @@ versions = fixture.DiscoveryList(v2=True, v3=False) self.requests_mock.get(BASE_URL, status_code=300, json=versions) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) self.assertRaises(exceptions.DiscoveryFailure, disc.create_client, version=(3, 0)) @@ -556,7 +566,9 @@ def test_available_keystone_data(self): self.requests_mock.get(BASE_URL, status_code=300, text=V3_VERSION_LIST) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual((2, 0), versions[0]['version']) @@ -587,7 +599,9 @@ v1_url = "%sv1/" % BASE_URL v2_url = "%sv2/" % BASE_URL - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual((1, 0), versions[0]['version']) @@ -618,7 +632,9 @@ v1_url = "%sv1/" % BASE_URL v2_url = "%sv2/" % BASE_URL - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual((1, 0), versions[0]['version']) @@ -664,7 +680,9 @@ text = jsonutils.dumps({'versions': version_list}) self.requests_mock.get(BASE_URL, text=text) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) # deprecated is allowed by default versions = disc.version_data(allow_deprecated=False) @@ -686,7 +704,9 @@ text = jsonutils.dumps({'versions': version_list}) self.requests_mock.get(BASE_URL, text=text) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual(0, len(versions)) @@ -702,7 +722,9 @@ version_list = fixture.DiscoveryList(BASE_URL, v2=False, v3_status=status) self.requests_mock.get(BASE_URL, json=version_list) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) versions = disc.version_data() self.assertEqual(0, len(versions)) @@ -732,7 +754,9 @@ text = jsonutils.dumps({'versions': version_list}) self.requests_mock.get(BASE_URL, text=text) - disc = discover.Discover(auth_url=BASE_URL) + # Creating Discover not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + disc = discover.Discover(auth_url=BASE_URL) # raw_version_data will return all choices, even invalid ones versions = disc.raw_version_data() diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_ec2utils.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_ec2utils.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_ec2utils.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_ec2utils.py 2015-09-09 04:34:24.000000000 +0000 @@ -17,12 +17,14 @@ import testtools from keystoneclient.contrib.ec2 import utils +from keystoneclient.tests.unit import client_fixtures class Ec2SignerTest(testtools.TestCase): def setUp(self): super(Ec2SignerTest, self).setUp() + self.useFixture(client_fixtures.Deprecations()) self.access = '966afbde20b84200ae4e62e09acf46b2' self.secret = '89cdf9e94e2643cab35b8b8ac5a51f83' self.signer = utils.Ec2Signer(self.secret) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_hacking_checks.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_hacking_checks.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_hacking_checks.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_hacking_checks.py 2015-09-09 04:34:24.000000000 +0000 @@ -21,6 +21,9 @@ class TestCheckOsloNamespaceImports(testtools.TestCase): + def setUp(self): + super(TestCheckOsloNamespaceImports, self).setUp() + self.useFixture(client_fixtures.Deprecations()) # We are patching pep8 so that only the check under test is actually # installed. diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_http.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_http.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_http.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_http.py 2015-09-09 04:34:24.000000000 +0000 @@ -28,7 +28,7 @@ def get_client(): cl = httpclient.HTTPClient(username="username", password="password", - tenant_id="tenant", auth_url="auth_test") + project_id="tenant", auth_url="auth_test") return cl @@ -56,18 +56,23 @@ TEST_URL = 'http://127.0.0.1:5000/hi' def test_unauthorized_client_requests(self): - cl = get_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_client() self.assertRaises(exceptions.AuthorizationFailure, cl.get, '/hi') self.assertRaises(exceptions.AuthorizationFailure, cl.post, '/hi') self.assertRaises(exceptions.AuthorizationFailure, cl.put, '/hi') self.assertRaises(exceptions.AuthorizationFailure, cl.delete, '/hi') def test_get(self): - cl = get_authed_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_authed_client() self.stub_url('GET', text=RESPONSE_BODY) - resp, body = cl.get("/hi") + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get("/hi") self.assertEqual(self.requests_mock.last_request.method, 'GET') self.assertEqual(self.requests_mock.last_request.url, self.TEST_URL) @@ -78,14 +83,18 @@ self.assertEqual(body, {"hi": "there"}) def test_get_error_with_plaintext_resp(self): - cl = get_authed_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_authed_client() self.stub_url('GET', status_code=400, text='Some evil plaintext string') self.assertRaises(exceptions.BadRequest, cl.get, '/hi') def test_get_error_with_json_resp(self): - cl = get_authed_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_authed_client() err_response = { "error": { "code": 400, @@ -96,17 +105,21 @@ self.stub_url('GET', status_code=400, json=err_response) exc_raised = False try: - cl.get('/hi') + with self.deprecations.expect_deprecations_here(): + cl.get('/hi') except exceptions.BadRequest as exc: exc_raised = True self.assertEqual(exc.message, "Error message string") self.assertTrue(exc_raised, 'Exception not raised.') def test_post(self): - cl = get_authed_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_authed_client() self.stub_url('POST') - cl.post("/hi", body=[1, 2, 3]) + with self.deprecations.expect_deprecations_here(): + cl.post("/hi", body=[1, 2, 3]) self.assertEqual(self.requests_mock.last_request.method, 'POST') self.assertEqual(self.requests_mock.last_request.body, '[1, 2, 3]') @@ -117,13 +130,18 @@ def test_forwarded_for(self): ORIGINAL_IP = "10.100.100.1" - cl = httpclient.HTTPClient(username="username", password="password", - tenant_id="tenant", auth_url="auth_test", - original_ip=ORIGINAL_IP) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient(username="username", + password="password", + project_id="tenant", + auth_url="auth_test", + original_ip=ORIGINAL_IP) self.stub_url('GET') - cl.request(self.TEST_URL, 'GET') + with self.deprecations.expect_deprecations_here(): + cl.request(self.TEST_URL, 'GET') forwarded = "for=%s;by=%s" % (ORIGINAL_IP, httpclient.USER_AGENT) self.assertRequestHeaderEqual('Forwarded', forwarded) @@ -167,7 +185,8 @@ self.requests_mock.register_uri(method, url, text=response, status_code=status_code) - return httpclient.request(url, method, **kwargs) + with self.deprecations.expect_deprecations_here(): + return httpclient.request(url, method, **kwargs) def test_basic_params(self): method = 'GET' diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_https.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_https.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_https.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_https.py 2015-09-09 04:34:24.000000000 +0000 @@ -28,8 +28,8 @@ def get_client(): cl = httpclient.HTTPClient(username="username", password="password", - tenant_id="tenant", auth_url="auth_test", - cacert="ca.pem", key="key.pem", cert="cert.pem") + project_id="tenant", auth_url="auth_test", + cacert="ca.pem", cert=('cert.pem', "key.pem")) return cl @@ -42,19 +42,15 @@ class ClientTest(utils.TestCase): - def setUp(self): - super(ClientTest, self).setUp() - self.request_patcher = mock.patch.object(requests, 'request', - self.mox.CreateMockAnything()) - self.request_patcher.start() - self.addCleanup(self.request_patcher.stop) - @mock.patch.object(requests, 'request') def test_get(self, MOCK_REQUEST): MOCK_REQUEST.return_value = FAKE_RESPONSE - cl = get_authed_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_authed_client() - resp, body = cl.get("/hi") + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get("/hi") # this may become too tightly couple later mock_args, mock_kwargs = MOCK_REQUEST.call_args @@ -71,9 +67,12 @@ @mock.patch.object(requests, 'request') def test_post(self, MOCK_REQUEST): MOCK_REQUEST.return_value = FAKE_RESPONSE - cl = get_authed_client() + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = get_authed_client() - cl.post("/hi", body=[1, 2, 3]) + with self.deprecations.expect_deprecations_here(): + cl.post("/hi", body=[1, 2, 3]) # this may become too tightly couple later mock_args, mock_kwargs = MOCK_REQUEST.call_args @@ -88,13 +87,16 @@ @mock.patch.object(requests, 'request') def test_post_auth(self, MOCK_REQUEST): MOCK_REQUEST.return_value = FAKE_RESPONSE - cl = httpclient.HTTPClient( - username="username", password="password", tenant_id="tenant", - auth_url="auth_test", cacert="ca.pem", key="key.pem", - cert="cert.pem") + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient( + username="username", password="password", project_id="tenant", + auth_url="auth_test", cacert="ca.pem", + cert=('cert.pem', 'key.pem')) cl.management_url = "https://127.0.0.1:5000" cl.auth_token = "token" - cl.post("/hi", body=[1, 2, 3]) + with self.deprecations.expect_deprecations_here(): + cl.post("/hi", body=[1, 2, 3]) # this may become too tightly couple later mock_args, mock_kwargs = MOCK_REQUEST.call_args diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_keyring.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_keyring.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_keyring.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_keyring.py 2015-09-09 04:34:24.000000000 +0000 @@ -19,6 +19,7 @@ from keystoneclient import httpclient from keystoneclient.tests.unit import utils from keystoneclient.tests.unit.v2_0 import client_fixtures +from keystoneclient import utils as client_utils try: import keyring # noqa @@ -86,8 +87,10 @@ """Ensure that if we don't have use_keyring set in the client that the keyring is never accessed. """ - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - tenant_id=TENANT_ID, auth_url=AUTH_URL) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, + project_id=TENANT_ID, auth_url=AUTH_URL) # stub and check that a new token is received method = 'get_raw_token_from_identity_service' @@ -103,8 +106,10 @@ self.assertFalse(self.memory_keyring.set_password_called) def test_build_keyring_key(self): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - tenant_id=TENANT_ID, auth_url=AUTH_URL) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, + project_id=TENANT_ID, auth_url=AUTH_URL) keyring_key = cl._build_keyring_key(auth_url=AUTH_URL, username=USERNAME, @@ -117,14 +122,16 @@ (AUTH_URL, TENANT_ID, TENANT, TOKEN, USERNAME)) def test_set_and_get_keyring_expired(self): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - tenant_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, + project_id=TENANT_ID, auth_url=AUTH_URL, + use_keyring=True) # set an expired token into the keyring auth_ref = access.AccessInfo.factory(body=PROJECT_SCOPED_TOKEN) expired = timeutils.utcnow() - datetime.timedelta(minutes=30) - auth_ref['token']['expires'] = timeutils.isotime(expired) + auth_ref['token']['expires'] = client_utils.isotime(expired) self.memory_keyring.password = pickle.dumps(auth_ref) # stub and check that a new token is received, so not using expired @@ -145,14 +152,16 @@ PROJECT_SCOPED_TOKEN['access']['token']['expires']) def test_get_keyring(self): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - tenant_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, + project_id=TENANT_ID, auth_url=AUTH_URL, + use_keyring=True) # set an token into the keyring auth_ref = access.AccessInfo.factory(body=PROJECT_SCOPED_TOKEN) future = timeutils.utcnow() + datetime.timedelta(minutes=30) - auth_ref['token']['expires'] = timeutils.isotime(future) + auth_ref['token']['expires'] = client_utils.isotime(future) self.memory_keyring.password = pickle.dumps(auth_ref) # don't stub get_raw_token so will fail if authenticate happens @@ -161,9 +170,11 @@ self.assertTrue(self.memory_keyring.fetched) def test_set_keyring(self): - cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, - tenant_id=TENANT_ID, auth_url=AUTH_URL, - use_keyring=True) + # Creating a HTTPClient not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD, + project_id=TENANT_ID, auth_url=AUTH_URL, + use_keyring=True) # stub and check that a new token is received method = 'get_raw_token_from_identity_service' diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_memcache_crypt.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_memcache_crypt.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_memcache_crypt.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_memcache_crypt.py 2015-09-09 04:34:24.000000000 +0000 @@ -14,9 +14,14 @@ import testtools from keystoneclient.middleware import memcache_crypt +from keystoneclient.tests.unit import client_fixtures class MemcacheCryptPositiveTests(testtools.TestCase): + def setUp(self): + super(MemcacheCryptPositiveTests, self).setUp() + self.useFixture(client_fixtures.Deprecations()) + def _setup_keys(self, strategy): return memcache_crypt.derive_keys(b'token', b'secret', strategy) @@ -49,7 +54,7 @@ len(keys['MAC'])) self.assertNotEqual(keys['ENCRYPTION'], keys['MAC']) - self.assertIn('strategy', keys.keys()) + self.assertIn('strategy', keys) def test_key_strategy_diff(self): k1 = self._setup_keys(b'MAC') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_s3_token_middleware.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_s3_token_middleware.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_s3_token_middleware.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_s3_token_middleware.py 2015-09-09 04:34:24.000000000 +0000 @@ -20,6 +20,7 @@ import webob from keystoneclient.middleware import s3_token +from keystoneclient.tests.unit import client_fixtures from keystoneclient.tests.unit import utils @@ -221,6 +222,10 @@ class S3TokenMiddlewareTestUtil(testtools.TestCase): + def setUp(self): + super(S3TokenMiddlewareTestUtil, self).setUp() + self.useFixture(client_fixtures.Deprecations()) + def test_split_path_failed(self): self.assertRaises(ValueError, s3_token.split_path, '') self.assertRaises(ValueError, s3_token.split_path, '/') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_session.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_session.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/test_session.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/test_session.py 2015-09-09 04:34:24.000000000 +0000 @@ -244,10 +244,77 @@ # The exception should contain the URL and details about the SSL error msg = _('SSL exception connecting to %(url)s: %(error)s') % { 'url': self.TEST_URL, 'error': error} - self.assertRaisesRegex(exceptions.SSLError, - msg, - session.get, - self.TEST_URL) + six.assertRaisesRegex(self, + exceptions.SSLError, + msg, + session.get, + self.TEST_URL) + + def test_mask_password_in_http_log_response(self): + session = client_session.Session() + + def fake_debug(msg): + self.assertNotIn('verybadpass', msg) + + logger = mock.Mock(isEnabledFor=mock.Mock(return_value=True)) + logger.debug = mock.Mock(side_effect=fake_debug) + body = { + "connection_info": { + "driver_volume_type": "iscsi", + "data": { + "auth_password": "verybadpass", + "target_discovered": False, + "encrypted": False, + "qos_specs": None, + "target_iqn": ("iqn.2010-10.org.openstack:volume-" + "744d2085-8e78-40a5-8659-ef3cffb2480e"), + "target_portal": "172.99.69.228:3260", + "volume_id": "744d2085-8e78-40a5-8659-ef3cffb2480e", + "target_lun": 1, + "access_mode": "rw", + "auth_username": "verybadusername", + "auth_method": "CHAP"}}} + body_json = jsonutils.dumps(body) + response = mock.Mock(text=body_json, status_code=200, headers={}) + session._http_log_response(response, logger) + self.assertEqual(1, logger.debug.call_count) + + +class TCPKeepAliveAdapter(utils.TestCase): + + @mock.patch.object(client_session, 'socket') + @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') + def test_init_poolmanager_all_options(self, mock_parent_init_poolmanager, + mock_socket): + # properties expected to be in socket. + mock_socket.TCP_KEEPIDLE = mock.sentinel.TCP_KEEPIDLE + mock_socket.TCP_KEEPCNT = mock.sentinel.TCP_KEEPCNT + mock_socket.TCP_KEEPINTVL = mock.sentinel.TCP_KEEPINTVL + desired_opts = [mock_socket.TCP_KEEPIDLE, mock_socket.TCP_KEEPCNT, + mock_socket.TCP_KEEPINTVL] + + adapter = client_session.TCPKeepAliveAdapter() + adapter.init_poolmanager() + + call_args, call_kwargs = mock_parent_init_poolmanager.call_args + called_socket_opts = call_kwargs['socket_options'] + call_options = [opt for (protocol, opt, value) in called_socket_opts] + for opt in desired_opts: + self.assertIn(opt, call_options) + + @mock.patch.object(client_session, 'socket') + @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') + def test_init_poolmanager(self, mock_parent_init_poolmanager, mock_socket): + spec = ['IPPROTO_TCP', 'TCP_NODELAY', 'SOL_SOCKET', 'SO_KEEPALIVE'] + mock_socket.mock_add_spec(spec) + adapter = client_session.TCPKeepAliveAdapter() + adapter.init_poolmanager() + + call_args, call_kwargs = mock_parent_init_poolmanager.call_args + called_socket_opts = call_kwargs['socket_options'] + call_options = [opt for (protocol, opt, value) in called_socket_opts] + self.assertEqual([mock_socket.TCP_NODELAY, mock_socket.SO_KEEPALIVE], + call_options) class RedirectTests(utils.TestCase): @@ -336,7 +403,8 @@ def _s(self, k=None, **kwargs): k = k or kwargs - return client_session.Session.construct(k) + with self.deprecations.expect_deprecations_here(): + return client_session.Session.construct(k) def test_verify(self): self.assertFalse(self._s(insecure=True).verify) @@ -364,7 +432,7 @@ Takes Parameters such that it can throw exceptions at the right times. """ - TEST_TOKEN = 'aToken' + TEST_TOKEN = utils.TestCase.TEST_TOKEN TEST_USER_ID = 'aUser' TEST_PROJECT_ID = 'aProject' @@ -414,7 +482,7 @@ def get_token(self, session): self.get_token_called = True - return 'aToken' + return utils.TestCase.TEST_TOKEN def get_endpoint(self, session, **kwargs): self.get_endpoint_called = True @@ -800,7 +868,8 @@ sess = client_session.Session() adpt = adapter.Adapter(sess, auth=auth) - self.assertEqual(self.TEST_TOKEN, adpt.get_token()) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(self.TEST_TOKEN, adpt.get_token()) self.assertTrue(auth.get_token_called) def test_adapter_connect_retries(self): diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/utils.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/utils.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/utils.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/utils.py 2015-09-09 04:34:24.000000000 +0000 @@ -12,12 +12,9 @@ import logging import sys -import time import uuid import fixtures -import mock -from mox3 import mox from oslo_serialization import jsonutils import requests from requests_mock.contrib import fixture @@ -25,37 +22,31 @@ from six.moves.urllib import parse as urlparse import testtools +from keystoneclient.tests.unit import client_fixtures + class TestCase(testtools.TestCase): - TEST_DOMAIN_ID = '1' - TEST_DOMAIN_NAME = 'aDomain' + TEST_DOMAIN_ID = uuid.uuid4().hex + TEST_DOMAIN_NAME = uuid.uuid4().hex TEST_GROUP_ID = uuid.uuid4().hex TEST_ROLE_ID = uuid.uuid4().hex - TEST_TENANT_ID = '1' - TEST_TENANT_NAME = 'aTenant' - TEST_TOKEN = 'aToken' - TEST_TRUST_ID = 'aTrust' - TEST_USER = 'test' + TEST_TENANT_ID = uuid.uuid4().hex + TEST_TENANT_NAME = uuid.uuid4().hex + TEST_TOKEN = uuid.uuid4().hex + TEST_TRUST_ID = uuid.uuid4().hex + TEST_USER = uuid.uuid4().hex TEST_USER_ID = uuid.uuid4().hex TEST_ROOT_URL = 'http://127.0.0.1:5000/' def setUp(self): super(TestCase, self).setUp() - self.mox = mox.Mox() - self.logger = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG)) - self.time_patcher = mock.patch.object(time, 'time', lambda: 1234) - self.time_patcher.start() + self.deprecations = self.useFixture(client_fixtures.Deprecations()) + self.logger = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG)) self.requests_mock = self.useFixture(fixture.Fixture()) - def tearDown(self): - self.time_patcher.stop() - self.mox.UnsetStubs() - self.mox.VerifyAll() - super(TestCase, self).tearDown() - def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs): if not base_url: base_url = self.TEST_URL @@ -179,7 +170,7 @@ def clear_module(self): cleared_modules = {} - for fullname in sys.modules.keys(): + for fullname in list(sys.modules): if (fullname == self.module or fullname.startswith(self.module + '.')): cleared_modules[fullname] = sys.modules.pop(fullname) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_access.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_access.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_access.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_access.py 2015-09-09 04:34:24.000000000 +0000 @@ -45,10 +45,13 @@ self.assertIsNone(auth_ref.tenant_name) self.assertIsNone(auth_ref.tenant_id) - self.assertIsNone(auth_ref.auth_url) - self.assertIsNone(auth_ref.management_url) + with self.deprecations.expect_deprecations_here(): + self.assertIsNone(auth_ref.auth_url) + with self.deprecations.expect_deprecations_here(): + self.assertIsNone(auth_ref.management_url) - self.assertFalse(auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertFalse(auth_ref.scoped) self.assertFalse(auth_ref.domain_scoped) self.assertFalse(auth_ref.project_scoped) self.assertFalse(auth_ref.trust_scoped) @@ -98,15 +101,20 @@ self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) - self.assertEqual(auth_ref.auth_url, ('http://public.com:5000/v2.0',)) - self.assertEqual(auth_ref.management_url, ('http://admin:35357/v2.0',)) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(auth_ref.auth_url, + ('http://public.com:5000/v2.0',)) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(auth_ref.management_url, + ('http://admin:35357/v2.0',)) self.assertEqual(auth_ref.project_domain_id, 'default') self.assertEqual(auth_ref.project_domain_name, 'Default') self.assertEqual(auth_ref.user_domain_id, 'default') self.assertEqual(auth_ref.user_domain_name, 'Default') - self.assertTrue(auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(auth_ref.scoped) self.assertTrue(auth_ref.project_scoped) self.assertFalse(auth_ref.domain_scoped) @@ -127,7 +135,8 @@ self.assertEqual(auth_ref.user_domain_id, 'default') self.assertEqual(auth_ref.user_domain_name, 'Default') self.assertEqual(auth_ref.role_names, ['role1', 'role2']) - self.assertFalse(auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertFalse(auth_ref.scoped) def test_grizzly_token(self): grizzly_token = self.examples.TOKEN_RESPONSES[ diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_auth.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_auth.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_auth.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_auth.py 2015-09-09 04:34:24.000000000 +0000 @@ -67,7 +67,7 @@ self.stub_auth(response_list=[{'json': resp_a, 'headers': headers}, {'json': resp_b, 'headers': headers}]) - cs = client.Client(tenant_id=self.TEST_TENANT_ID, + cs = client.Client(project_id=self.TEST_TENANT_ID, auth_url=self.TEST_URL, username=self.TEST_USER, password=self.TEST_TOKEN) @@ -93,10 +93,11 @@ # where with assertRaises(exceptions.Unauthorized): doesn't work # right def client_create_wrapper(): - client.Client(username=self.TEST_USER, - password="bad_key", - tenant_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + client.Client(username=self.TEST_USER, + password="bad_key", + project_id=self.TEST_TENANT_ID, + auth_url=self.TEST_URL) self.assertRaises(exceptions.Unauthorized, client_create_wrapper) self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY) @@ -108,10 +109,11 @@ self.stub_auth(base_url=self.TEST_ADMIN_URL, json=self.TEST_RESPONSE_DICT) - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - tenant_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cs = client.Client(username=self.TEST_USER, + password=self.TEST_TOKEN, + project_id=self.TEST_TENANT_ID, + auth_url=self.TEST_URL) self.assertEqual(cs.management_url, self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] @@ -123,10 +125,11 @@ def test_authenticate_success_password_scoped(self): self.stub_auth(json=self.TEST_RESPONSE_DICT) - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - tenant_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cs = client.Client(username=self.TEST_USER, + password=self.TEST_TOKEN, + project_id=self.TEST_TENANT_ID, + auth_url=self.TEST_URL) self.assertEqual(cs.management_url, self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] ['endpoints'][0]["adminURL"]) @@ -140,9 +143,10 @@ self.stub_auth(json=self.TEST_RESPONSE_DICT) - cs = client.Client(username=self.TEST_USER, - password=self.TEST_TOKEN, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cs = client.Client(username=self.TEST_USER, + password=self.TEST_TOKEN, + auth_url=self.TEST_URL) self.assertEqual(cs.auth_token, self.TEST_RESPONSE_DICT["access"]["token"]["id"]) self.assertFalse('serviceCatalog' in cs.service_catalog.catalog) @@ -157,12 +161,14 @@ self.stub_url('GET', [fake_url], json=fake_resp, base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - cl = client.Client(auth_url=self.TEST_URL, - token=fake_token) + with self.deprecations.expect_deprecations_here(): + cl = client.Client(auth_url=self.TEST_URL, + token=fake_token) json_body = jsonutils.loads(self.requests_mock.last_request.body) self.assertEqual(json_body['auth']['token']['id'], fake_token) - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') @@ -173,9 +179,10 @@ self.TEST_REQUEST_BODY['auth']['token'] = {'id': self.TEST_TOKEN} self.stub_auth(json=self.TEST_RESPONSE_DICT) - cs = client.Client(token=self.TEST_TOKEN, - tenant_id=self.TEST_TENANT_ID, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cs = client.Client(token=self.TEST_TOKEN, + project_id=self.TEST_TENANT_ID, + auth_url=self.TEST_URL) self.assertEqual(cs.management_url, self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3] ['endpoints'][0]["adminURL"]) @@ -192,10 +199,11 @@ "id": self.TEST_TRUST_ID} self.stub_auth(json=response) - cs = client.Client(token=self.TEST_TOKEN, - tenant_id=self.TEST_TENANT_ID, - trust_id=self.TEST_TRUST_ID, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cs = client.Client(token=self.TEST_TOKEN, + project_id=self.TEST_TENANT_ID, + trust_id=self.TEST_TRUST_ID, + auth_url=self.TEST_URL) self.assertTrue(cs.auth_ref.trust_scoped) self.assertEqual(cs.auth_ref.trust_id, self.TEST_TRUST_ID) self.assertEqual(cs.auth_ref.trustee_user_id, self.TEST_USER) @@ -209,8 +217,9 @@ self.stub_auth(json=self.TEST_RESPONSE_DICT) - cs = client.Client(token=self.TEST_TOKEN, - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cs = client.Client(token=self.TEST_TOKEN, + auth_url=self.TEST_URL) self.assertEqual(cs.auth_token, self.TEST_RESPONSE_DICT["access"]["token"]["id"]) self.assertFalse('serviceCatalog' in cs.service_catalog.catalog) @@ -225,15 +234,17 @@ self.stub_url('GET', [fake_url], json=fake_resp, base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT) - cl = client.Client(username='exampleuser', - password='password', - tenant_name='exampleproject', - auth_url=self.TEST_URL) + with self.deprecations.expect_deprecations_here(): + cl = client.Client(username='exampleuser', + password='password', + project_name='exampleproject', + auth_url=self.TEST_URL) self.assertEqual(cl.auth_token, self.TEST_TOKEN) # the token returned from the authentication will be used - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') @@ -242,7 +253,8 @@ # then override that token and the new token shall be used cl.auth_token = fake_token - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') @@ -251,7 +263,8 @@ # if we clear that overridden token then we fall back to the original del cl.auth_token - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_client.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_client.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_client.py 2015-09-09 04:34:24.000000000 +0000 @@ -34,7 +34,8 @@ password='password', auth_url=self.TEST_URL) self.assertIsNotNone(c.auth_ref) - self.assertFalse(c.auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertFalse(c.auth_ref.scoped) self.assertFalse(c.auth_ref.domain_scoped) self.assertFalse(c.auth_ref.project_scoped) self.assertIsNone(c.auth_ref.trust_id) @@ -48,10 +49,11 @@ c = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL) self.assertIsNotNone(c.auth_ref) - self.assertTrue(c.auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(c.auth_ref.scoped) self.assertTrue(c.auth_ref.project_scoped) self.assertFalse(c.auth_ref.domain_scoped) self.assertIsNone(c.auth_ref.trust_id) @@ -65,12 +67,13 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL) cache = json.dumps(cl.auth_ref) new_client = client.Client(auth_ref=json.loads(cache)) self.assertIsNotNone(new_client.auth_ref) - self.assertTrue(new_client.auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(new_client.auth_ref.scoped) self.assertTrue(new_client.auth_ref.project_scoped) self.assertFalse(new_client.auth_ref.domain_scoped) self.assertIsNone(new_client.auth_ref.trust_id) @@ -85,15 +88,15 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL) cache = json.dumps(cl.auth_ref) new_auth_url = "http://new-public:5000/v2.0" new_client = client.Client(auth_ref=json.loads(cache), auth_url=new_auth_url) self.assertIsNotNone(new_client.auth_ref) - self.assertTrue(new_client.auth_ref.scoped) - self.assertTrue(new_client.auth_ref.scoped) + with self.deprecations.expect_deprecations_here(): + self.assertTrue(new_client.auth_ref.scoped) self.assertTrue(new_client.auth_ref.project_scoped) self.assertFalse(new_client.auth_ref.domain_scoped) self.assertIsNone(new_client.auth_ref.trust_id) @@ -130,7 +133,7 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL) self.assertEqual(cl.management_url, admin_url) @@ -144,7 +147,7 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL, region_name='North') self.assertEqual(cl.service_catalog.url_for(service_type='image'), @@ -152,7 +155,7 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL, region_name='South') self.assertEqual(cl.service_catalog.url_for(service_type='image'), @@ -161,7 +164,7 @@ def test_client_without_auth_params(self): self.assertRaises(exceptions.AuthorizationFailure, client.Client, - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL) def test_client_params(self): diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_service_catalog.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_service_catalog.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_service_catalog.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_service_catalog.py 2015-09-09 04:34:24.000000000 +0000 @@ -48,7 +48,9 @@ def test_service_catalog_regions(self): self.AUTH_RESPONSE_BODY['access']['region_name'] = "North" - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) + # Setting region_name on the catalog is deprecated. + with self.deprecations.expect_deprecations_here(): + auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) sc = auth_ref.service_catalog url = sc.url_for(service_type='image', endpoint_type='publicURL') @@ -133,7 +135,9 @@ def test_service_catalog_param_overrides_body_region(self): self.AUTH_RESPONSE_BODY['access']['region_name'] = "North" - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) + # Setting region_name on the catalog is deprecated. + with self.deprecations.expect_deprecations_here(): + auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) sc = auth_ref.service_catalog url = sc.url_for(service_type='image') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_shell.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_shell.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_shell.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_shell.py 2015-09-09 04:34:24.000000000 +0000 @@ -39,7 +39,7 @@ super(ShellTests, self).setUp() - self.old_environment = os.environ.copy() + self.addCleanup(setattr, os, 'environ', os.environ.copy()) os.environ = { 'OS_USERNAME': DEFAULT_USERNAME, 'OS_PASSWORD': DEFAULT_PASSWORD, @@ -58,10 +58,6 @@ self.stub_auth(json=self.token, base_url=DEFAULT_AUTH_URL) - def tearDown(self): - os.environ = self.old_environment - super(ShellTests, self).tearDown() - def run_command(self, cmd): orig = sys.stdout try: diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_tokens.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_tokens.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/test_tokens.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/test_tokens.py 2015-09-09 04:34:24.000000000 +0000 @@ -168,6 +168,9 @@ token_fixture = fixture.V2Token(token_id=id_) self.stub_url('GET', ['tokens', id_], json=token_fixture) + token_data = self.client.tokens.get_token_data(id_) + self.assertEqual(token_fixture, token_data) + token_ref = self.client.tokens.validate(id_) self.assertIsInstance(token_ref, tokens.Token) self.assertEqual(id_, token_ref.id) @@ -178,6 +181,9 @@ id_ = uuid.uuid4().hex # The server is expected to return 404 if the token is invalid. self.stub_url('GET', ['tokens', id_], status_code=404) + + self.assertRaises(exceptions.NotFound, + self.client.tokens.get_token_data, id_) self.assertRaises(exceptions.NotFound, self.client.tokens.validate, id_) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/utils.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/utils.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v2_0/utils.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v2_0/utils.py 2015-09-09 04:34:24.000000000 +0000 @@ -78,11 +78,12 @@ def setUp(self): super(TestCase, self).setUp() - self.client = client.Client(username=self.TEST_USER, - token=self.TEST_TOKEN, - tenant_name=self.TEST_TENANT_NAME, - auth_url=self.TEST_URL, - endpoint=self.TEST_URL) + + # Creating a Client not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + self.client = client.Client(token=self.TEST_TOKEN, + auth_url=self.TEST_URL, + endpoint=self.TEST_URL) def stub_auth(self, **kwargs): self.stub_url('POST', ['tokens'], **kwargs) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/client_fixtures.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/client_fixtures.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/client_fixtures.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/client_fixtures.py 2015-09-09 04:34:24.000000000 +0000 @@ -16,26 +16,18 @@ from keystoneclient import fixture -def unscoped_token(): - return fixture.V3Token(user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser', - user_domain_id='4e6893b7ba0b4006840c3845660b86ed', - user_domain_name='exampledomain', - expires='2010-11-01T03:32:15-05:00') - - -def domain_scoped_token(): - f = fixture.V3Token(user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser', - user_domain_id='4e6893b7ba0b4006840c3845660b86ed', - user_domain_name='exampledomain', - expires='2010-11-01T03:32:15-05:00', - domain_id='8e9283b7ba0b1038840c3842058b86ab', - domain_name='anotherdomain', - audit_chain_id=uuid.uuid4().hex) +def unscoped_token(**kwargs): + return fixture.V3Token(**kwargs) - f.add_role(id='76e72a', name='admin') - f.add_role(id='f4f392', name='member') + +def domain_scoped_token(**kwargs): + kwargs.setdefault('audit_chain_id', uuid.uuid4().hex) + f = fixture.V3Token(**kwargs) + if not f.domain_id: + f.set_domain_scope() + + f.add_role(name='admin') + f.add_role(name='member') region = 'RegionOne' s = f.add_service('volume') @@ -71,20 +63,15 @@ return f -def project_scoped_token(): - f = fixture.V3Token(user_id='c4da488862bd435c9e6c0275a0d0e49a', - user_name='exampleuser', - user_domain_id='4e6893b7ba0b4006840c3845660b86ed', - user_domain_name='exampledomain', - expires='2010-11-01T03:32:15-05:00', - project_id='225da22d3ce34b15877ea70b2a575f58', - project_name='exampleproject', - project_domain_id='4e6893b7ba0b4006840c3845660b86ed', - project_domain_name='exampledomain', - audit_chain_id=uuid.uuid4().hex) +def project_scoped_token(**kwargs): + kwargs.setdefault('audit_chain_id', uuid.uuid4().hex) + f = fixture.V3Token(**kwargs) - f.add_role(id='76e72a', name='admin') - f.add_role(id='f4f392', name='member') + if not f.project_id: + f.set_project_scope() + + f.add_role(name='admin') + f.add_role(name='member') region = 'RegionOne' tenant = '225da22d3ce34b15877ea70b2a575f58' @@ -122,7 +109,7 @@ return f -AUTH_SUBJECT_TOKEN = '3e2813b7ba0b4006840c3825860b86ed' +AUTH_SUBJECT_TOKEN = uuid.uuid4().hex AUTH_RESPONSE_HEADERS = { 'X-Subject-Token': AUTH_SUBJECT_TOKEN, @@ -130,19 +117,11 @@ def auth_response_body(): - f = fixture.V3Token(user_id='567', - user_name='test', - user_domain_id='1', - user_domain_name='aDomain', - expires='2010-11-01T03:32:15-05:00', - project_domain_id='123', - project_domain_name='aDomain', - project_id='345', - project_name='aTenant', - audit_chain_id=uuid.uuid4().hex) + f = fixture.V3Token(audit_chain_id=uuid.uuid4().hex) + f.set_project_scope() - f.add_role(id='76e72a', name='admin') - f.add_role(id='f4f392', name='member') + f.add_role(name='admin') + f.add_role(name='member') s = f.add_service('compute', name='nova') s.add_standard_endpoints( @@ -175,13 +154,6 @@ def trust_token(): - return fixture.V3Token(user_id='0ca8f6', - user_name='exampleuser', - user_domain_id='4e6893b7ba0b4006840c3845660b86ed', - user_domain_name='exampledomain', - expires='2010-11-01T03:32:15-05:00', - trust_id='fe0aef', - trust_impersonation=False, - trustee_user_id='0ca8f6', - trustor_user_id='bd263c', - audit_chain_id=uuid.uuid4().hex) + f = fixture.V3Token(audit_chain_id=uuid.uuid4().hex) + f.set_trust_scope() + return f diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_access.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_access.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_access.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_access.py 2015-09-09 04:34:24.000000000 +0000 @@ -38,10 +38,10 @@ self.assertIn('methods', auth_ref) self.assertNotIn('catalog', auth_ref) - self.assertEqual(auth_ref.auth_token, - '3e2813b7ba0b4006840c3825860b86ed') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') + self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, + auth_ref.auth_token) + self.assertEqual(UNSCOPED_TOKEN.user_name, auth_ref.username) + self.assertEqual(UNSCOPED_TOKEN.user_id, auth_ref.user_id) self.assertEqual(auth_ref.role_ids, []) self.assertEqual(auth_ref.role_names, []) @@ -49,15 +49,18 @@ self.assertIsNone(auth_ref.project_name) self.assertIsNone(auth_ref.project_id) - self.assertIsNone(auth_ref.auth_url) - self.assertIsNone(auth_ref.management_url) + with self.deprecations.expect_deprecations_here(): + self.assertIsNone(auth_ref.auth_url) + with self.deprecations.expect_deprecations_here(): + self.assertIsNone(auth_ref.management_url) self.assertFalse(auth_ref.domain_scoped) self.assertFalse(auth_ref.project_scoped) - self.assertEqual(auth_ref.user_domain_id, - '4e6893b7ba0b4006840c3845660b86ed') - self.assertEqual(auth_ref.user_domain_name, 'exampledomain') + self.assertEqual(UNSCOPED_TOKEN.user_domain_id, + auth_ref.user_domain_id) + self.assertEqual(UNSCOPED_TOKEN.user_domain_name, + auth_ref.user_domain_name) self.assertIsNone(auth_ref.project_domain_id) self.assertIsNone(auth_ref.project_domain_name) @@ -92,24 +95,24 @@ self.assertIn('catalog', auth_ref) self.assertTrue(auth_ref['catalog']) - self.assertEqual(auth_ref.auth_token, - '3e2813b7ba0b4006840c3825860b86ed') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') - - self.assertEqual(auth_ref.role_ids, ['76e72a', 'f4f392']) - self.assertEqual(auth_ref.role_names, ['admin', 'member']) - - self.assertEqual(auth_ref.domain_name, 'anotherdomain') - self.assertEqual(auth_ref.domain_id, - '8e9283b7ba0b1038840c3842058b86ab') + self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, + auth_ref.auth_token) + self.assertEqual(DOMAIN_SCOPED_TOKEN.user_name, auth_ref.username) + self.assertEqual(DOMAIN_SCOPED_TOKEN.user_id, auth_ref.user_id) + + self.assertEqual(DOMAIN_SCOPED_TOKEN.role_ids, auth_ref.role_ids) + self.assertEqual(DOMAIN_SCOPED_TOKEN.role_names, auth_ref.role_names) + + self.assertEqual(DOMAIN_SCOPED_TOKEN.domain_name, auth_ref.domain_name) + self.assertEqual(DOMAIN_SCOPED_TOKEN.domain_id, auth_ref.domain_id) self.assertIsNone(auth_ref.project_name) self.assertIsNone(auth_ref.project_id) - self.assertEqual(auth_ref.user_domain_id, - '4e6893b7ba0b4006840c3845660b86ed') - self.assertEqual(auth_ref.user_domain_name, 'exampledomain') + self.assertEqual(DOMAIN_SCOPED_TOKEN.user_domain_id, + auth_ref.user_domain_id) + self.assertEqual(DOMAIN_SCOPED_TOKEN.user_domain_name, + auth_ref.user_domain_name) self.assertIsNone(auth_ref.project_domain_id) self.assertIsNone(auth_ref.project_domain_name) @@ -130,36 +133,40 @@ self.assertIn('catalog', auth_ref) self.assertTrue(auth_ref['catalog']) - self.assertEqual(auth_ref.auth_token, - '3e2813b7ba0b4006840c3825860b86ed') - self.assertEqual(auth_ref.username, 'exampleuser') - self.assertEqual(auth_ref.user_id, 'c4da488862bd435c9e6c0275a0d0e49a') + self.assertEqual(client_fixtures.AUTH_SUBJECT_TOKEN, + auth_ref.auth_token) + self.assertEqual(PROJECT_SCOPED_TOKEN.user_name, auth_ref.username) + self.assertEqual(PROJECT_SCOPED_TOKEN.user_id, auth_ref.user_id) - self.assertEqual(auth_ref.role_ids, ['76e72a', 'f4f392']) - self.assertEqual(auth_ref.role_names, ['admin', 'member']) + self.assertEqual(PROJECT_SCOPED_TOKEN.role_ids, auth_ref.role_ids) + self.assertEqual(PROJECT_SCOPED_TOKEN.role_names, auth_ref.role_names) self.assertIsNone(auth_ref.domain_name) self.assertIsNone(auth_ref.domain_id) - self.assertEqual(auth_ref.project_name, 'exampleproject') - self.assertEqual(auth_ref.project_id, - '225da22d3ce34b15877ea70b2a575f58') + self.assertEqual(PROJECT_SCOPED_TOKEN.project_name, + auth_ref.project_name) + self.assertEqual(PROJECT_SCOPED_TOKEN.project_id, auth_ref.project_id) self.assertEqual(auth_ref.tenant_name, auth_ref.project_name) self.assertEqual(auth_ref.tenant_id, auth_ref.project_id) - self.assertEqual(auth_ref.auth_url, - ('http://public.com:5000/v3',)) - self.assertEqual(auth_ref.management_url, - ('http://admin:35357/v3',)) - - self.assertEqual(auth_ref.project_domain_id, - '4e6893b7ba0b4006840c3845660b86ed') - self.assertEqual(auth_ref.project_domain_name, 'exampledomain') - - self.assertEqual(auth_ref.user_domain_id, - '4e6893b7ba0b4006840c3845660b86ed') - self.assertEqual(auth_ref.user_domain_name, 'exampledomain') + with self.deprecations.expect_deprecations_here(): + self.assertEqual(auth_ref.auth_url, + ('http://public.com:5000/v3',)) + with self.deprecations.expect_deprecations_here(): + self.assertEqual(auth_ref.management_url, + ('http://admin:35357/v3',)) + + self.assertEqual(PROJECT_SCOPED_TOKEN.project_domain_id, + auth_ref.project_domain_id) + self.assertEqual(PROJECT_SCOPED_TOKEN.project_domain_name, + auth_ref.project_domain_name) + + self.assertEqual(PROJECT_SCOPED_TOKEN.user_domain_id, + auth_ref.user_domain_id) + self.assertEqual(PROJECT_SCOPED_TOKEN.user_domain_name, + auth_ref.user_domain_name) self.assertFalse(auth_ref.domain_scoped) self.assertTrue(auth_ref.project_scoped) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_auth_manager.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_auth_manager.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_auth_manager.py 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_auth_manager.py 2015-09-09 04:34:24.000000000 +0000 @@ -0,0 +1,72 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import uuid + +from keystoneclient.auth.identity import v3 +from keystoneclient import fixture +from keystoneclient import session +from keystoneclient.tests.unit.v3 import utils +from keystoneclient.v3 import auth +from keystoneclient.v3 import client + + +class AuthProjectsTest(utils.TestCase): + + def setUp(self): + super(AuthProjectsTest, self).setUp() + + self.v3token = fixture.V3Token() + self.stub_auth(json=self.v3token) + + self.stub_url('GET', + [], + json={'version': fixture.V3Discovery(self.TEST_URL)}) + + self.auth = v3.Password(auth_url=self.TEST_URL, + user_id=self.v3token.user_id, + password=uuid.uuid4().hex) + self.session = session.Session(auth=self.auth) + self.client = client.Client(session=self.session) + + def create_resource(self, id=None, name=None, **kwargs): + kwargs['id'] = id or uuid.uuid4().hex + kwargs['name'] = name or uuid.uuid4().hex + return kwargs + + def test_get_projects(self): + body = {'projects': [self.create_resource(), + self.create_resource(), + self.create_resource()]} + + self.stub_url('GET', ['auth', 'projects'], json=body) + + projects = self.client.auth.projects() + + self.assertEqual(3, len(projects)) + + for p in projects: + self.assertIsInstance(p, auth.Project) + + def test_get_domains(self): + body = {'domains': [self.create_resource(), + self.create_resource(), + self.create_resource()]} + + self.stub_url('GET', ['auth', 'domains'], json=body) + + domains = self.client.auth.domains() + + self.assertEqual(3, len(domains)) + + for d in domains: + self.assertIsInstance(d, auth.Domain) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_auth_oidc.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_auth_oidc.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_auth_oidc.py 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_auth_oidc.py 2015-09-09 04:34:24.000000000 +0000 @@ -0,0 +1,190 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import uuid + +from oslo_config import fixture as config +from six.moves import urllib +import testtools + +from keystoneclient.auth import conf +from keystoneclient.contrib.auth.v3 import oidc +from keystoneclient import session +from keystoneclient.tests.unit.v3 import utils + + +ACCESS_TOKEN_ENDPOINT_RESP = {"access_token": "z5H1ITZLlJVDHQXqJun", + "token_type": "bearer", + "expires_in": 3599, + "scope": "profile", + "refresh_token": "DCERsh83IAhu9bhavrp"} + +KEYSTONE_TOKEN_VALUE = uuid.uuid4().hex +UNSCOPED_TOKEN = { + "token": { + "issued_at": "2014-06-09T09:48:59.643406Z", + "extras": {}, + "methods": ["oidc"], + "expires_at": "2014-06-09T10:48:59.643375Z", + "user": { + "OS-FEDERATION": { + "identity_provider": { + "id": "bluepages" + }, + "protocol": { + "id": "oidc" + }, + "groups": [ + {"id": "1764fa5cf69a49a4918131de5ce4af9a"} + ] + }, + "id": "oidc_user%40example.com", + "name": "oidc_user@example.com" + } + } +} + + +class AuthenticateOIDCTests(utils.TestCase): + + GROUP = 'auth' + + def setUp(self): + super(AuthenticateOIDCTests, self).setUp() + + self.conf_fixture = self.useFixture(config.Config()) + conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + + self.session = session.Session() + + self.IDENTITY_PROVIDER = 'bluepages' + self.PROTOCOL = 'oidc' + self.USER_NAME = 'oidc_user@example.com' + self.PASSWORD = uuid.uuid4().hex + self.CLIENT_ID = uuid.uuid4().hex + self.CLIENT_SECRET = uuid.uuid4().hex + self.ACCESS_TOKEN_ENDPOINT = 'https://localhost:8020/oidc/token' + self.FEDERATION_AUTH_URL = '%s/%s' % ( + self.TEST_URL, + 'OS-FEDERATION/identity_providers/bluepages/protocols/oidc/auth') + + self.oidcplugin = oidc.OidcPassword( + self.TEST_URL, + self.IDENTITY_PROVIDER, + self.PROTOCOL, + username=self.USER_NAME, + password=self.PASSWORD, + client_id=self.CLIENT_ID, + client_secret=self.CLIENT_SECRET, + access_token_endpoint=self.ACCESS_TOKEN_ENDPOINT) + + @testtools.skip("TypeError: __init__() got an unexpected keyword" + " argument 'project_name'") + def test_conf_params(self): + """Ensure OpenID Connect config options work.""" + + section = uuid.uuid4().hex + identity_provider = uuid.uuid4().hex + protocol = uuid.uuid4().hex + username = uuid.uuid4().hex + password = uuid.uuid4().hex + client_id = uuid.uuid4().hex + client_secret = uuid.uuid4().hex + access_token_endpoint = uuid.uuid4().hex + + self.conf_fixture.config(auth_section=section, group=self.GROUP) + conf.register_conf_options(self.conf_fixture.conf, group=self.GROUP) + + self.conf_fixture.register_opts(oidc.OidcPassword.get_options(), + group=section) + self.conf_fixture.config(auth_plugin='v3oidcpassword', + identity_provider=identity_provider, + protocol=protocol, + username=username, + password=password, + client_id=client_id, + client_secret=client_secret, + access_token_endpoint=access_token_endpoint, + group=section) + + a = conf.load_from_conf_options(self.conf_fixture.conf, self.GROUP) + self.assertEqual(identity_provider, a.identity_provider) + self.assertEqual(protocol, a.protocol) + self.assertEqual(username, a.username) + self.assertEqual(password, a.password) + self.assertEqual(client_id, a.client_id) + self.assertEqual(client_secret, a.client_secret) + self.assertEqual(access_token_endpoint, a.access_token_endpoint) + + def test_initial_call_to_get_access_token(self): + """Test initial call, expect JSON access token.""" + + # Mock the output that creates the access token + self.requests_mock.post( + self.ACCESS_TOKEN_ENDPOINT, + json=ACCESS_TOKEN_ENDPOINT_RESP) + + # Prep all the values and send the request + grant_type = 'password' + scope = 'profile email' + client_auth = (self.CLIENT_ID, self.CLIENT_SECRET) + payload = {'grant_type': grant_type, 'username': self.USER_NAME, + 'password': self.PASSWORD, 'scope': scope} + res = self.oidcplugin._get_access_token(self.session, + client_auth, + payload, + self.ACCESS_TOKEN_ENDPOINT) + + # Verify the request matches the expected structure + self.assertEqual(self.ACCESS_TOKEN_ENDPOINT, res.request.url) + self.assertEqual('POST', res.request.method) + encoded_payload = urllib.parse.urlencode(payload) + self.assertEqual(encoded_payload, res.request.body) + + def test_second_call_to_protected_url(self): + """Test subsequent call, expect Keystone token.""" + + # Mock the output that creates the keystone token + self.requests_mock.post( + self.FEDERATION_AUTH_URL, + json=UNSCOPED_TOKEN, + headers={'X-Subject-Token': KEYSTONE_TOKEN_VALUE}) + + # Prep all the values and send the request + access_token = uuid.uuid4().hex + headers = {'Authorization': 'Bearer ' + access_token} + res = self.oidcplugin._get_keystone_token(self.session, + headers, + self.FEDERATION_AUTH_URL) + + # Verify the request matches the expected structure + self.assertEqual(self.FEDERATION_AUTH_URL, res.request.url) + self.assertEqual('POST', res.request.method) + self.assertEqual(headers['Authorization'], + res.request.headers['Authorization']) + + def test_end_to_end_workflow(self): + """Test full OpenID Connect workflow.""" + + # Mock the output that creates the access token + self.requests_mock.post( + self.ACCESS_TOKEN_ENDPOINT, + json=ACCESS_TOKEN_ENDPOINT_RESP) + + # Mock the output that creates the keystone token + self.requests_mock.post( + self.FEDERATION_AUTH_URL, + json=UNSCOPED_TOKEN, + headers={'X-Subject-Token': KEYSTONE_TOKEN_VALUE}) + + response = self.oidcplugin.get_unscoped_auth_ref(self.session) + self.assertEqual(KEYSTONE_TOKEN_VALUE, response.auth_token) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_auth.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_auth.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_auth.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_auth.py 2015-09-09 04:34:24.000000000 +0000 @@ -229,7 +229,8 @@ body = jsonutils.loads(self.requests_mock.last_request.body) self.assertEqual(body['auth']['identity']['token']['id'], fake_token) - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') @@ -321,13 +322,14 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL) self.assertEqual(cl.auth_token, self.TEST_TOKEN) # the token returned from the authentication will be used - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') @@ -336,7 +338,8 @@ # then override that token and the new token shall be used cl.auth_token = fake_token - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') @@ -345,7 +348,8 @@ # if we clear that overridden token then we fall back to the original del cl.auth_token - resp, body = cl.get(fake_url) + with self.deprecations.expect_deprecations_here(): + resp, body = cl.get(fake_url) self.assertEqual(fake_resp, body) token = self.requests_mock.last_request.headers.get('X-Auth-Token') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_client.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_client.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_client.py 2015-09-09 04:34:24.000000000 +0000 @@ -27,71 +27,67 @@ class KeystoneClientTest(utils.TestCase): def test_unscoped_init(self): - self.stub_auth(json=client_fixtures.unscoped_token()) + token = client_fixtures.unscoped_token() + self.stub_auth(json=token) - c = client.Client(user_domain_name='exampledomain', - username='exampleuser', + c = client.Client(user_domain_name=token.user_domain_name, + username=token.user_name, password='password', auth_url=self.TEST_URL) self.assertIsNotNone(c.auth_ref) self.assertFalse(c.auth_ref.domain_scoped) self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(c.auth_user_id, - 'c4da488862bd435c9e6c0275a0d0e49a') + self.assertEqual(token.user_id, c.auth_user_id) self.assertFalse(c.has_service_catalog()) - self.assertEqual('c4da488862bd435c9e6c0275a0d0e49a', - c.get_user_id(session=None)) + self.assertEqual(token.user_id, c.get_user_id(session=None)) self.assertIsNone(c.get_project_id(session=None)) def test_domain_scoped_init(self): - self.stub_auth(json=client_fixtures.domain_scoped_token()) + token = client_fixtures.domain_scoped_token() + self.stub_auth(json=token) - c = client.Client(user_id='c4da488862bd435c9e6c0275a0d0e49a', + c = client.Client(user_id=token.user_id, password='password', - domain_name='exampledomain', + domain_name=token.domain_name, auth_url=self.TEST_URL) self.assertIsNotNone(c.auth_ref) self.assertTrue(c.auth_ref.domain_scoped) self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(c.auth_user_id, - 'c4da488862bd435c9e6c0275a0d0e49a') - self.assertEqual(c.auth_domain_id, - '8e9283b7ba0b1038840c3842058b86ab') + self.assertEqual(token.user_id, c.auth_user_id) + self.assertEqual(token.domain_id, c.auth_domain_id) def test_project_scoped_init(self): - self.stub_auth(json=client_fixtures.project_scoped_token()), + token = client_fixtures.project_scoped_token() + self.stub_auth(json=token), - c = client.Client(user_id='c4da488862bd435c9e6c0275a0d0e49a', + c = client.Client(user_id=token.user_id, password='password', - user_domain_name='exampledomain', - project_name='exampleproject', + user_domain_name=token.user_domain_name, + project_name=token.project_name, auth_url=self.TEST_URL) self.assertIsNotNone(c.auth_ref) self.assertFalse(c.auth_ref.domain_scoped) self.assertTrue(c.auth_ref.project_scoped) - self.assertEqual(c.auth_user_id, - 'c4da488862bd435c9e6c0275a0d0e49a') - self.assertEqual(c.auth_tenant_id, - '225da22d3ce34b15877ea70b2a575f58') - self.assertEqual('c4da488862bd435c9e6c0275a0d0e49a', - c.get_user_id(session=None)) - self.assertEqual('225da22d3ce34b15877ea70b2a575f58', - c.get_project_id(session=None)) + self.assertEqual(token.user_id, c.auth_user_id) + self.assertEqual(token.project_id, c.auth_tenant_id) + self.assertEqual(token.user_id, c.get_user_id(session=None)) + self.assertEqual(token.project_id, c.get_project_id(session=None)) def test_auth_ref_load(self): - self.stub_auth(json=client_fixtures.project_scoped_token()) + token = client_fixtures.project_scoped_token() + self.stub_auth(json=token) - c = client.Client(user_id='c4da488862bd435c9e6c0275a0d0e49a', + c = client.Client(user_id=token.user_id, password='password', - project_id='225da22d3ce34b15877ea70b2a575f58', + project_id=token.project_id, auth_url=self.TEST_URL) cache = json.dumps(c.auth_ref) new_client = client.Client(auth_ref=json.loads(cache)) self.assertIsNotNone(new_client.auth_ref) self.assertFalse(new_client.auth_ref.domain_scoped) self.assertTrue(new_client.auth_ref.project_scoped) - self.assertEqual(new_client.username, 'exampleuser') + self.assertEqual(token.user_name, new_client.username) self.assertIsNone(new_client.password) self.assertEqual(new_client.management_url, 'http://admin:35357/v3') @@ -99,13 +95,22 @@ def test_auth_ref_load_with_overridden_arguments(self): new_auth_url = 'https://newkeystone.com/v3' - self.stub_auth(json=client_fixtures.project_scoped_token()) - self.stub_auth(json=client_fixtures.project_scoped_token(), - base_url=new_auth_url) + user_id = uuid.uuid4().hex + user_name = uuid.uuid4().hex + project_id = uuid.uuid4().hex + + first = client_fixtures.project_scoped_token(user_id=user_id, + user_name=user_name, + project_id=project_id) + second = client_fixtures.project_scoped_token(user_id=user_id, + user_name=user_name, + project_id=project_id) + self.stub_auth(json=first) + self.stub_auth(json=second, base_url=new_auth_url) - c = client.Client(user_id='c4da488862bd435c9e6c0275a0d0e49a', + c = client.Client(user_id=user_id, password='password', - project_id='225da22d3ce34b15877ea70b2a575f58', + project_id=project_id, auth_url=self.TEST_URL) cache = json.dumps(c.auth_ref) new_client = client.Client(auth_ref=json.loads(cache), @@ -113,28 +118,29 @@ self.assertIsNotNone(new_client.auth_ref) self.assertFalse(new_client.auth_ref.domain_scoped) self.assertTrue(new_client.auth_ref.project_scoped) - self.assertEqual(new_client.auth_url, new_auth_url) - self.assertEqual(new_client.username, 'exampleuser') + self.assertEqual(new_auth_url, new_client.auth_url) + self.assertEqual(user_name, new_client.username) self.assertIsNone(new_client.password) self.assertEqual(new_client.management_url, 'http://admin:35357/v3') def test_trust_init(self): - self.stub_auth(json=client_fixtures.trust_token()) + token = client_fixtures.trust_token() + self.stub_auth(json=token) - c = client.Client(user_domain_name='exampledomain', - username='exampleuser', + c = client.Client(user_domain_name=token.user_domain_name, + username=token.user_name, password='password', auth_url=self.TEST_URL, - trust_id='fe0aef') + trust_id=token.trust_id) self.assertIsNotNone(c.auth_ref) self.assertFalse(c.auth_ref.domain_scoped) self.assertFalse(c.auth_ref.project_scoped) - self.assertEqual(c.auth_ref.trust_id, 'fe0aef') - self.assertEqual(c.auth_ref.trustee_user_id, '0ca8f6') - self.assertEqual(c.auth_ref.trustor_user_id, 'bd263c') + self.assertEqual(token.trust_id, c.auth_ref.trust_id) + self.assertEqual(token.trustee_user_id, c.auth_ref.trustee_user_id) + self.assertEqual(token.trustor_user_id, c.auth_ref.trustor_user_id) self.assertTrue(c.auth_ref.trust_scoped) - self.assertEqual(c.auth_user_id, '0ca8f6') + self.assertEqual(token.user_id, c.auth_user_id) def test_init_err_no_auth_url(self): self.assertRaises(exceptions.AuthorizationFailure, @@ -185,12 +191,13 @@ def test_client_with_region_name_passes_to_service_catalog(self): # NOTE(jamielennox): this is deprecated behaviour that should be # removed ASAP, however must remain compatible. + self.deprecations.expect_deprecations() self.stub_auth(json=client_fixtures.auth_response_body()) cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL, region_name='North') self.assertEqual(cl.service_catalog.url_for(service_type='image'), @@ -198,7 +205,7 @@ cl = client.Client(username='exampleuser', password='password', - tenant_name='exampleproject', + project_name='exampleproject', auth_url=self.TEST_URL, region_name='South') self.assertEqual(cl.service_catalog.url_for(service_type='image'), diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_credentials.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_credentials.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_credentials.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_credentials.py 2015-09-09 04:34:24.000000000 +0000 @@ -42,6 +42,7 @@ def test_create_data_not_blob(self): # Test create operation with previous, deprecated "data" argument, # which should be translated into "blob" at the API call level + self.deprecations.expect_deprecations() req_ref = self.new_ref() api_ref = self._ref_data_not_blob(req_ref) req_ref.pop('id') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_domains.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_domains.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_domains.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_domains.py 2015-09-09 04:34:24.000000000 +0000 @@ -30,6 +30,12 @@ kwargs.setdefault('name', uuid.uuid4().hex) return kwargs + def test_filter_for_default_domain_by_id(self): + ref = self.new_ref(id='default') + super(DomainTests, self).test_list_by_id( + ref=ref, + id=ref['id']) + def test_list_filter_name(self): super(DomainTests, self).test_list(name='adomain123') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_federation.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_federation.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_federation.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_federation.py 2015-09-09 04:34:24.000000000 +0000 @@ -278,6 +278,16 @@ for obj, ref_obj in zip(returned, expected): self.assertEqual(obj.to_dict(), ref_obj) + def test_list_by_id(self): + # The test in the parent class needs to be overridden because it + # assumes globally unique IDs, which is not the case with protocol IDs + # (which are contextualized per identity provider). + ref = self.new_ref() + super(ProtocolTests, self).test_list_by_id( + ref=ref, + identity_provider=ref['identity_provider'], + id=ref['id']) + def test_list_params(self): request_args = self.new_ref() filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex} diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_oauth1.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_oauth1.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_oauth1.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_oauth1.py 2015-09-09 04:34:24.000000000 +0000 @@ -14,7 +14,6 @@ import uuid import mock -from oslo_utils import timeutils import six from six.moves.urllib import parse as urlparse from testtools import matchers @@ -22,13 +21,13 @@ from keystoneclient import session from keystoneclient.tests.unit.v3 import client_fixtures from keystoneclient.tests.unit.v3 import utils +from keystoneclient import utils as client_utils from keystoneclient.v3.contrib.oauth1 import access_tokens from keystoneclient.v3.contrib.oauth1 import auth from keystoneclient.v3.contrib.oauth1 import consumers from keystoneclient.v3.contrib.oauth1 import request_tokens try: - import oauthlib from oauthlib import oauth1 except ImportError: oauth1 = None @@ -90,7 +89,7 @@ def _new_oauth_token_with_expires_at(self): key, secret, token = self._new_oauth_token() - expires_at = timeutils.strtime() + expires_at = client_utils.strtime() params = {'oauth_token': key, 'oauth_token_secret': secret, 'oauth_expires_at': expires_at} @@ -103,16 +102,8 @@ """ self.assertThat(auth_header, matchers.StartsWith('OAuth ')) - auth_header = auth_header[len('OAuth '):] - # NOTE(stevemar): In newer versions of oauthlib there is - # an additional argument for getting oauth parameters. - # Adding a conditional here to revert back to no arguments - # if an earlier version is detected. - if tuple(oauthlib.__version__.split('.')) > ('0', '6', '1'): - header_params = oauth_client.get_oauth_params(None) - else: - header_params = oauth_client.get_oauth_params() - parameters = dict(header_params) + parameters = dict( + oauth1.rfc5849.utils.parse_authorization_header(auth_header)) self.assertEqual('HMAC-SHA1', parameters['oauth_signature_method']) self.assertEqual('1.0', parameters['oauth_version']) @@ -128,9 +119,6 @@ if oauth_client.callback_uri: self.assertEqual(oauth_client.callback_uri, parameters['oauth_callback']) - if oauth_client.timestamp: - self.assertEqual(oauth_client.timestamp, - parameters['oauth_timestamp']) return parameters @@ -229,8 +217,8 @@ resource_owner_key=request_key, resource_owner_secret=request_secret, signature_method=oauth1.SIGNATURE_HMAC, - verifier=verifier, - timestamp=expires_at) + verifier=verifier) + self._validate_oauth_headers(req_headers['Authorization'], oauth_client) @@ -260,7 +248,8 @@ access_key=access_key, access_secret=access_secret) s = session.Session(auth=a) - t = s.get_token() + with self.deprecations.expect_deprecations_here(): + t = s.get_token() self.assertEqual(self.TEST_TOKEN, t) OAUTH_REQUEST_BODY = { diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_role_assignments.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_role_assignments.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_role_assignments.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_role_assignments.py 2015-09-09 04:34:24.000000000 +0000 @@ -71,6 +71,15 @@ self.assertEqual(len(ref_list), len(returned_list)) [self.assertIsInstance(r, self.model) for r in returned_list] + def test_list_by_id(self): + # It doesn't make sense to "list role assignments by ID" at all, given + # that they don't have globally unique IDs in the first place. But + # calling RoleAssignmentsManager.list(id=...) should still raise a + # TypeError when given an unexpected keyword argument 'id', so we don't + # actually have to modify the test in the superclass... I just wanted + # to make a note here in case the superclass changes. + super(RoleAssignmentsTests, self).test_list_by_id() + def test_list_params(self): ref_list = self.TEST_USER_PROJECT_LIST self.stub_entity('GET', diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_roles.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_roles.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_roles.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_roles.py 2015-09-09 04:34:24.000000000 +0000 @@ -59,6 +59,20 @@ self.manager.grant(role=ref['id'], domain=domain_id, user=user_id, os_inherit_extension_inherited=True) + def test_project_role_grant_inherited(self): + user_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref = self.new_ref() + + self.stub_url('PUT', + ['OS-INHERIT', 'projects', project_id, 'users', user_id, + self.collection_key, ref['id'], + 'inherited_to_projects'], + status_code=204) + + self.manager.grant(role=ref['id'], project=project_id, user=user_id, + os_inherit_extension_inherited=True) + def test_domain_group_role_grant(self): group_id = uuid.uuid4().hex domain_id = uuid.uuid4().hex @@ -85,6 +99,20 @@ self.manager.grant(role=ref['id'], domain=domain_id, group=group_id, os_inherit_extension_inherited=True) + def test_project_group_role_grant_inherited(self): + group_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref = self.new_ref() + + self.stub_url('PUT', + ['OS-INHERIT', 'projects', project_id, 'groups', + group_id, self.collection_key, ref['id'], + 'inherited_to_projects'], + status_code=204) + + self.manager.grant(role=ref['id'], project=project_id, group=group_id, + os_inherit_extension_inherited=True) + def test_domain_role_list(self): user_id = uuid.uuid4().hex domain_id = uuid.uuid4().hex @@ -113,6 +141,23 @@ self.assertThat(ref_list, matchers.HasLength(len(returned_list))) [self.assertIsInstance(r, self.model) for r in returned_list] + def test_project_user_role_list_inherited(self): + user_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref_list = [self.new_ref(), self.new_ref()] + + self.stub_entity('GET', + ['OS-INHERIT', + 'projects', project_id, 'users', user_id, + self.collection_key, 'inherited_to_projects'], + entity=ref_list) + + returned_list = self.manager.list(project=project_id, user=user_id, + os_inherit_extension_inherited=True) + + self.assertThat(ref_list, matchers.HasLength(len(returned_list))) + [self.assertIsInstance(r, self.model) for r in returned_list] + def test_domain_group_role_list(self): group_id = uuid.uuid4().hex domain_id = uuid.uuid4().hex @@ -141,6 +186,23 @@ self.assertThat(ref_list, matchers.HasLength(len(returned_list))) [self.assertIsInstance(r, self.model) for r in returned_list] + def test_project_group_role_list_inherited(self): + group_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref_list = [self.new_ref(), self.new_ref()] + + self.stub_entity('GET', + ['OS-INHERIT', + 'projects', project_id, 'groups', group_id, + self.collection_key, 'inherited_to_projects'], + entity=ref_list) + + returned_list = self.manager.list(project=project_id, group=group_id, + os_inherit_extension_inherited=True) + + self.assertThat(ref_list, matchers.HasLength(len(returned_list))) + [self.assertIsInstance(r, self.model) for r in returned_list] + def test_domain_role_check(self): user_id = uuid.uuid4().hex domain_id = uuid.uuid4().hex @@ -169,6 +231,21 @@ self.manager.check(role=ref['id'], domain=domain_id, user=user_id, os_inherit_extension_inherited=True) + def test_project_role_check_inherited(self): + user_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref = self.new_ref() + + self.stub_url('HEAD', + ['OS-INHERIT', + 'projects', project_id, 'users', user_id, + self.collection_key, ref['id'], + 'inherited_to_projects'], + status_code=204) + + self.manager.check(role=ref['id'], project=project_id, + user=user_id, os_inherit_extension_inherited=True) + def test_domain_group_role_check(self): return group_id = uuid.uuid4().hex @@ -197,6 +274,21 @@ self.manager.check(role=ref['id'], domain=domain_id, group=group_id, os_inherit_extension_inherited=True) + def test_project_group_role_check_inherited(self): + group_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref = self.new_ref() + + self.stub_url('HEAD', + ['OS-INHERIT', + 'projects', project_id, 'groups', group_id, + self.collection_key, ref['id'], + 'inherited_to_projects'], + status_code=204) + + self.manager.check(role=ref['id'], project=project_id, + group=group_id, os_inherit_extension_inherited=True) + def test_domain_role_revoke(self): user_id = uuid.uuid4().hex domain_id = uuid.uuid4().hex @@ -235,6 +327,20 @@ self.manager.revoke(role=ref['id'], domain=domain_id, user=user_id, os_inherit_extension_inherited=True) + def test_project_role_revoke_inherited(self): + user_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref = self.new_ref() + + self.stub_url('DELETE', + ['OS-INHERIT', 'projects', project_id, 'users', user_id, + self.collection_key, ref['id'], + 'inherited_to_projects'], + status_code=204) + + self.manager.revoke(role=ref['id'], project=project_id, + user=user_id, os_inherit_extension_inherited=True) + def test_domain_group_role_revoke_inherited(self): group_id = uuid.uuid4().hex domain_id = uuid.uuid4().hex @@ -250,6 +356,21 @@ group=group_id, os_inherit_extension_inherited=True) + def test_project_group_role_revoke_inherited(self): + group_id = uuid.uuid4().hex + project_id = uuid.uuid4().hex + ref = self.new_ref() + + self.stub_url('DELETE', + ['OS-INHERIT', 'projects', project_id, 'groups', + group_id, self.collection_key, ref['id'], + 'inherited_to_projects'], + status_code=204) + + self.manager.revoke(role=ref['id'], project=project_id, + group=group_id, + os_inherit_extension_inherited=True) + def test_project_role_grant(self): user_id = uuid.uuid4().hex project_id = uuid.uuid4().hex diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_service_catalog.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_service_catalog.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_service_catalog.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_service_catalog.py 2015-09-09 04:34:24.000000000 +0000 @@ -66,8 +66,10 @@ def test_service_catalog_regions(self): self.AUTH_RESPONSE_BODY['token']['region_name'] = "North" - auth_ref = access.AccessInfo.factory(self.RESPONSE, - self.AUTH_RESPONSE_BODY) + # Setting region_name on the catalog is deprecated. + with self.deprecations.expect_deprecations_here(): + auth_ref = access.AccessInfo.factory(self.RESPONSE, + self.AUTH_RESPONSE_BODY) sc = auth_ref.service_catalog url = sc.url_for(service_type='image', endpoint_type='public') @@ -149,7 +151,9 @@ def test_service_catalog_param_overrides_body_region(self): self.AUTH_RESPONSE_BODY['token']['region_name'] = "North" - auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) + # Passing region_name to service catalog is deprecated. + with self.deprecations.expect_deprecations_here(): + auth_ref = access.AccessInfo.factory(None, self.AUTH_RESPONSE_BODY) sc = auth_ref.service_catalog url = sc.url_for(service_type='image') diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_tokens.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_tokens.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_tokens.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_tokens.py 2015-09-09 04:34:24.000000000 +0000 @@ -53,6 +53,10 @@ self.examples.v3_UUID_TOKEN_DEFAULT] self.stub_url('GET', ['auth', 'tokens'], headers={'X-Subject-Token': token_id, }, json=token_ref) + + token_data = self.client.tokens.get_token_data(token_id) + self.assertEqual(token_data, token_ref) + access_info = self.client.tokens.validate(token_id) self.assertRequestHeaderEqual('X-Subject-Token', token_id) @@ -77,6 +81,9 @@ # When the token is invalid the server typically returns a 404. token_id = uuid.uuid4().hex self.stub_url('GET', ['auth', 'tokens'], status_code=404) + + self.assertRaises(exceptions.NotFound, + self.client.tokens.get_token_data, token_id) self.assertRaises(exceptions.NotFound, self.client.tokens.validate, token_id) @@ -87,6 +94,11 @@ self.examples.v3_UUID_TOKEN_DEFAULT] self.stub_url('GET', ['auth', 'tokens'], headers={'X-Subject-Token': token_id, }, json=token_ref) + + token_data = self.client.tokens.get_token_data(token_id) + self.assertQueryStringIs() + self.assertIn('catalog', token_data['token']) + access_info = self.client.tokens.validate(token_id) self.assertQueryStringIs() @@ -99,6 +111,11 @@ self.examples.v3_UUID_TOKEN_UNSCOPED] self.stub_url('GET', ['auth', 'tokens'], headers={'X-Subject-Token': token_id, }, json=token_ref) + + token_data = self.client.tokens.get_token_data(token_id) + self.assertQueryStringIs() + self.assertNotIn('catalog', token_data['token']) + access_info = self.client.tokens.validate(token_id, include_catalog=False) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_users.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_users.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/test_users.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/test_users.py 2015-09-09 04:34:24.000000000 +0000 @@ -111,6 +111,7 @@ def test_create_with_project(self): # Can create a user with the deprecated project option rather than # default_project_id. + self.deprecations.expect_deprecations() ref = self.new_ref() self.stub_entity('POST', [self.collection_key], @@ -135,6 +136,8 @@ def test_create_with_project_and_default_project(self): # Can create a user with the deprecated project and default_project_id. # The backend call should only pass the default_project_id. + self.deprecations.expect_deprecations() + ref = self.new_ref() self.stub_entity('POST', @@ -180,6 +183,8 @@ def test_update_with_project(self): # Can update a user with the deprecated project option rather than # default_project_id. + self.deprecations.expect_deprecations() + ref = self.new_ref() req_ref = ref.copy() req_ref.pop('id') @@ -203,6 +208,8 @@ self.assertEntityRequestBodyIs(req_ref) def test_update_with_project_and_default_project(self, ref=None): + self.deprecations.expect_deprecations() + ref = self.new_ref() req_ref = ref.copy() req_ref.pop('id') @@ -230,8 +237,8 @@ new_password = uuid.uuid4().hex self.stub_url('POST', - [self.collection_key, self.TEST_USER, 'password']) - self.client.user_id = self.TEST_USER + [self.collection_key, self.TEST_USER_ID, 'password']) + self.client.user_id = self.TEST_USER_ID self.manager.update_password(old_password, new_password) exp_req_body = { @@ -240,8 +247,9 @@ } } - self.assertEqual(self.TEST_URL + '/users/test/password', - self.requests_mock.last_request.url) + self.assertEqual( + '%s/users/%s/password' % (self.TEST_URL, self.TEST_USER_ID), + self.requests_mock.last_request.url) self.assertRequestBodyIs(json=exp_req_body) self.assertNotIn(old_password, self.logger.output) self.assertNotIn(new_password, self.logger.output) diff -Nru python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/utils.py python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/utils.py --- python-keystoneclient-1.6.0/keystoneclient/tests/unit/v3/utils.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/tests/unit/v3/utils.py 2015-09-09 04:34:24.000000000 +0000 @@ -129,11 +129,12 @@ def setUp(self): super(TestCase, self).setUp() - self.client = client.Client(username=self.TEST_USER, - token=self.TEST_TOKEN, - tenant_name=self.TEST_TENANT_NAME, - auth_url=self.TEST_URL, - endpoint=self.TEST_URL) + + # Creating a Client not using session is deprecated. + with self.deprecations.expect_deprecations_here(): + self.client = client.Client(token=self.TEST_TOKEN, + auth_url=self.TEST_URL, + endpoint=self.TEST_URL) def stub_auth(self, subject_token=None, **kwargs): if not subject_token: @@ -245,6 +246,20 @@ return expected_path + def test_list_by_id(self, ref=None, **filter_kwargs): + """Test ``entities.list(id=x)`` being rewritten as ``GET /v3/entities/x``. + + This tests an edge case of each manager's list() implementation, to + ensure that it "does the right thing" when users call ``.list()`` + when they should have used ``.get()``. + + """ + if 'id' not in filter_kwargs: + ref = ref or self.new_ref() + filter_kwargs['id'] = ref['id'] + + self.assertRaises(TypeError, self.manager.list, **filter_kwargs) + def test_list(self, ref_list=None, expected_path=None, expected_query=None, **filter_kwargs): ref_list = ref_list or [self.new_ref(), self.new_ref()] diff -Nru python-keystoneclient-1.6.0/keystoneclient/utils.py python-keystoneclient-1.7.1/keystoneclient/utils.py --- python-keystoneclient-1.6.0/keystoneclient/utils.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/utils.py 2015-09-09 04:34:24.000000000 +0000 @@ -18,6 +18,7 @@ import sys from oslo_utils import encodeutils +from oslo_utils import timeutils import prettytable import six @@ -331,8 +332,42 @@ if self._enforcement == self.EXCEPT: raise TypeError(message) elif self._enforcement == self.WARN: - logger.warn(message) + logger.warning(message) return func(*args, **kwargs) return inner + + +_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' +_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' + + +def isotime(at=None, subsecond=False): + """Stringify time in ISO 8601 format.""" + + # Python provides a similar instance method for datetime.datetime objects + # called isoformat(). The format of the strings generated by isoformat() + # have a couple of problems: + # 1) The strings generated by isotime are used in tokens and other public + # APIs that we can't change without a deprecation period. The strings + # generated by isoformat are not the same format, so we can't just + # change to it. + # 2) The strings generated by isoformat do not include the microseconds if + # the value happens to be 0. This will likely show up as random failures + # as parsers may be written to always expect microseconds, and it will + # parse correctly most of the time. + + if not at: + at = timeutils.utcnow() + st = at.strftime(_ISO8601_TIME_FORMAT + if not subsecond + else _ISO8601_TIME_FORMAT_SUBSECOND) + tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' + st += ('Z' if tz == 'UTC' else tz) + return st + + +def strtime(at=None): + at = at or timeutils.utcnow() + return at.strftime(timeutils.PERFECT_TIME_FORMAT) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v2_0/client.py python-keystoneclient-1.7.1/keystoneclient/v2_0/client.py --- python-keystoneclient-1.6.0/keystoneclient/v2_0/client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v2_0/client.py 2015-09-09 04:34:24.000000000 +0000 @@ -14,6 +14,7 @@ # under the License. import logging +import warnings from keystoneclient.auth.identity import v2 as v2_auth from keystoneclient import exceptions @@ -79,6 +80,11 @@ If debug is enabled, it may show passwords in plain text as a part of its output. + .. warning:: + + Constructing an instance of this class without a session is + deprecated as of the 1.7.0 release and will be removed in the + 2.0.0 release. The client can be created and used like a user or in a strictly bootstrap mode. Normal operation expects a username, password, auth_url, @@ -130,6 +136,14 @@ def __init__(self, **kwargs): """Initialize a new client for the Keystone v2.0 API.""" + + if not kwargs.get('session'): + warnings.warn( + 'Constructing an instance of the ' + 'keystoneclient.v2_0.client.Client class without a session is ' + 'deprecated as of the 1.7.0 release and may be removed in ' + 'the 2.0.0 release.', DeprecationWarning) + super(Client, self).__init__(**kwargs) self.certificates = certificates.CertificatesManager(self._adapter) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v2_0/shell.py python-keystoneclient-1.7.1/keystoneclient/v2_0/shell.py --- python-keystoneclient-1.6.0/keystoneclient/v2_0/shell.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v2_0/shell.py 2015-09-09 04:34:24.000000000 +0000 @@ -15,7 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. """ -This module is pending deprecation in favor of python-openstackclient. +This module is deprecated as of the 1.7.0 release in favor of +python-openstackclient and may be removed in the 2.0.0 release. Bug fixes are welcome, but new features should be exposed to the CLI by python-openstackclient after being added to the python-keystoneclient library. diff -Nru python-keystoneclient-1.6.0/keystoneclient/v2_0/tokens.py python-keystoneclient-1.7.1/keystoneclient/v2_0/tokens.py --- python-keystoneclient-1.6.0/keystoneclient/v2_0/tokens.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v2_0/tokens.py 2015-09-09 04:34:24.000000000 +0000 @@ -84,6 +84,17 @@ """ return self._get('/tokens/%s' % base.getid(token), 'access') + def get_token_data(self, token): + """Fetch the data about a token from the identity server. + + :param str token: The token id. + + :rtype: dict + """ + url = '/tokens/%s' % token + resp, body = self.client.get(url) + return body + def validate_access_info(self, token): """Validate a token. @@ -100,10 +111,9 @@ return token.auth_token return base.getid(token) - url = '/tokens/%s' % calc_id(token) - resp, body = self.client.get(url) - access_info = access.AccessInfo.factory(resp=resp, body=body) - return access_info + token_id = calc_id(token) + body = self.get_token_data(token_id) + return access.AccessInfo.factory(auth_token=token_id, body=body) def get_revoked(self): """Returns the revoked tokens response. diff -Nru python-keystoneclient-1.6.0/keystoneclient/v2_0/users.py python-keystoneclient-1.7.1/keystoneclient/v2_0/users.py --- python-keystoneclient-1.6.0/keystoneclient/v2_0/users.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v2_0/users.py 2015-09-09 04:34:24.000000000 +0000 @@ -75,7 +75,8 @@ params = {"user": {"password": passwd, "original_password": origpasswd}} - return self._update("/OS-KSCRUD/users/%s" % self.api.user_id, params, + return self._update("/OS-KSCRUD/users/%s" % self.client.user_id, + params, response_key="access", method="PATCH", endpoint_filter={'interface': 'public'}, diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/auth.py python-keystoneclient-1.7.1/keystoneclient/v3/auth.py --- python-keystoneclient-1.6.0/keystoneclient/v3/auth.py 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/auth.py 2015-09-09 04:34:24.000000000 +0000 @@ -0,0 +1,81 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from keystoneclient import auth +from keystoneclient import base +from keystoneclient import exceptions + + +class Project(base.Resource): + """Represents an Identity project. + + Attributes: + * id: a uuid that identifies the project + * name: project name + * description: project description + * enabled: boolean to indicate if project is enabled + * parent_id: a uuid representing this project's parent in hierarchy + * parents: a list or a structured dict containing the parents of this + project in the hierarchy + * subtree: a list or a structured dict containing the subtree of this + project in the hierarchy + + """ + + +class Domain(base.Resource): + """Represents an Identity domain. + + Attributes: + * id: a uuid that identifies the domain + + """ + pass + + +class AuthManager(base.Manager): + """Retrieve auth context specific information. + + The information returned by the /auth routes are entirely dependant on the + authentication information provided by the user. + """ + + _PROJECTS_URL = '/auth/projects' + _DOMAINS_URL = '/auth/domains' + + def projects(self): + """List projects that this token can be rescoped to. + """ + try: + return self._list(self._PROJECTS_URL, + 'projects', + obj_class=Project) + except exceptions.EndpointNotFound: + endpoint_filter = {'interface': auth.AUTH_INTERFACE} + return self._list(self._PROJECTS_URL, + 'projects', + obj_class=Project, + endpoint_filter=endpoint_filter) + + def domains(self): + """List Domains that this token can be rescoped to. + """ + try: + return self._list(self._DOMAINS_URL, + 'domains', + obj_class=Domain) + except exceptions.EndpointNotFound: + endpoint_filter = {'interface': auth.AUTH_INTERFACE} + return self._list(self._DOMAINS_URL, + 'domains', + obj_class=Domain, + endpoint_filter=endpoint_filter) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/client.py python-keystoneclient-1.7.1/keystoneclient/v3/client.py --- python-keystoneclient-1.6.0/keystoneclient/v3/client.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/client.py 2015-09-09 04:34:24.000000000 +0000 @@ -14,6 +14,7 @@ # under the License. import logging +import warnings from oslo_serialization import jsonutils @@ -21,6 +22,7 @@ from keystoneclient import exceptions from keystoneclient import httpclient from keystoneclient.i18n import _ +from keystoneclient.v3 import auth from keystoneclient.v3.contrib import endpoint_filter from keystoneclient.v3.contrib import endpoint_policy from keystoneclient.v3.contrib import federation @@ -65,11 +67,13 @@ :param string project_domain_name: Project's domain name for project scoping. (optional) :param string tenant_name: Tenant name. (optional) - The tenant_name keyword argument is deprecated, - use project_name instead. + The tenant_name keyword argument is deprecated + as of the 1.7.0 release in favor of project_name + and may be removed in the 2.0.0 release. :param string tenant_id: Tenant id. (optional) - The tenant_id keyword argument is deprecated, - use project_id instead. + The tenant_id keyword argument is deprecated as of + the 1.7.0 release in favor of project_id and may + be removed in the 2.0.0 release. :param string auth_url: Identity service endpoint for authorization. :param string region_name: Name of a region to select when choosing an endpoint from the service catalog. @@ -80,6 +84,12 @@ :param integer timeout: Allows customization of the timeout for client http requests. (optional) + .. warning:: + + Constructing an instance of this class without a session is + deprecated as of the 1.7.0 release and will be removed in the + 2.0.0 release. + Example:: >>> from keystoneclient.v3 import client @@ -179,6 +189,14 @@ """Initialize a new client for the Keystone v3 API.""" super(Client, self).__init__(**kwargs) + if not kwargs.get('session'): + warnings.warn( + 'Constructing an instance of the ' + 'keystoneclient.v3.client.Client class without a session is ' + 'deprecated as of the 1.7.0 release and may be removed in ' + 'the 2.0.0 release.', DeprecationWarning) + + self.auth = auth.AuthManager(self._adapter) self.credentials = credentials.CredentialManager(self._adapter) self.ec2 = ec2.EC2Manager(self._adapter) self.endpoint_filter = endpoint_filter.EndpointFilterManager( diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/contrib/oauth1/access_tokens.py python-keystoneclient-1.7.1/keystoneclient/v3/contrib/oauth1/access_tokens.py --- python-keystoneclient-1.6.0/keystoneclient/v3/contrib/oauth1/access_tokens.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/contrib/oauth1/access_tokens.py 2015-09-09 04:34:24.000000000 +0000 @@ -40,7 +40,8 @@ resource_owner_secret=request_secret, signature_method=oauth1.SIGNATURE_HMAC, verifier=verifier) - url = self.api.get_endpoint(interface=auth.AUTH_INTERFACE).rstrip('/') + url = self.client.get_endpoint(interface=auth.AUTH_INTERFACE).rstrip( + '/') url, headers, body = oauth_client.sign(url + endpoint, http_method='POST') resp, body = self.client.post(endpoint, headers=headers) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/contrib/oauth1/request_tokens.py python-keystoneclient-1.7.1/keystoneclient/v3/contrib/oauth1/request_tokens.py --- python-keystoneclient-1.6.0/keystoneclient/v3/contrib/oauth1/request_tokens.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/contrib/oauth1/request_tokens.py 2015-09-09 04:34:24.000000000 +0000 @@ -63,7 +63,8 @@ client_secret=consumer_secret, signature_method=oauth1.SIGNATURE_HMAC, callback_uri="oob") - url = self.api.get_endpoint(interface=auth.AUTH_INTERFACE).rstrip("/") + url = self.client.get_endpoint(interface=auth.AUTH_INTERFACE).rstrip( + "/") url, headers, body = oauth_client.sign(url + endpoint, http_method='POST', headers=headers) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/contrib/trusts.py python-keystoneclient-1.7.1/keystoneclient/v3/contrib/trusts.py --- python-keystoneclient-1.6.0/keystoneclient/v3/contrib/trusts.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/contrib/trusts.py 2015-09-09 04:34:24.000000000 +0000 @@ -10,11 +10,10 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_utils import timeutils - from keystoneclient import base from keystoneclient import exceptions from keystoneclient.i18n import _ +from keystoneclient import utils class Trust(base.Resource): @@ -61,7 +60,7 @@ # Convert datetime.datetime expires_at to iso format string if expires_at: - expires_str = timeutils.isotime(at=expires_at, subsecond=True) + expires_str = utils.isotime(at=expires_at, subsecond=True) else: expires_str = None diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/credentials.py python-keystoneclient-1.7.1/keystoneclient/v3/credentials.py --- python-keystoneclient-1.6.0/keystoneclient/v3/credentials.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/credentials.py 2015-09-09 04:34:24.000000000 +0000 @@ -14,6 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. +from debtcollector import renames + from keystoneclient import base from keystoneclient.i18n import _ from keystoneclient import utils @@ -46,13 +48,13 @@ if blob is not None: return blob elif data is not None: - # FIXME(shardy): Passing data is deprecated. Provide an - # appropriate warning. return data else: raise ValueError( _("Credential requires blob to be specified")) + @renames.renamed_kwarg('data', 'blob', version='1.7.0', + removal_version='2.0.0') @utils.positional(1, enforcement=utils.positional.WARN) def create(self, user, type, blob=None, data=None, project=None, **kwargs): """Create a credential @@ -61,7 +63,8 @@ :type user: :class:`keystoneclient.v3.users.User` or str :param str type: credential type, should be either ``ec2`` or ``cert`` :param JSON blob: Credential data - :param JSON data: Deprecated, use blob instead. + :param JSON data: Deprecated as of the 1.7.0 release in favor of blob + and may by removed in the 2.0.0 release. :param project: Project, optional :type project: :class:`keystoneclient.v3.projects.Project` or str :param kwargs: Extra attributes passed to create. @@ -94,6 +97,8 @@ """ return super(CredentialManager, self).list(**kwargs) + @renames.renamed_kwarg('data', 'blob', version='1.7.0', + removal_version='2.0.0') @utils.positional(2, enforcement=utils.positional.WARN) def update(self, credential, user, type=None, blob=None, data=None, project=None, **kwargs): @@ -105,7 +110,8 @@ :type user: :class:`keystoneclient.v3.users.User` or str :param str type: credential type, should be either ``ec2`` or ``cert`` :param JSON blob: Credential data - :param JSON data: Deprecated, use blob instead. + :param JSON data: Deprecated as of the 1.7.0 release in favor of blob + and may be removed in the 2.0.0 release. :param project: Project :type project: :class:`keystoneclient.v3.projects.Project` or str :param kwargs: Extra attributes passed to create. diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/roles.py python-keystoneclient-1.7.1/keystoneclient/v3/roles.py --- python-keystoneclient-1.6.0/keystoneclient/v3/roles.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/roles.py 2015-09-09 04:34:24.000000000 +0000 @@ -50,8 +50,8 @@ params['domain_id'] = base.getid(domain) base_url = '/domains/%(domain_id)s' - if use_inherit_extension: - base_url = '/OS-INHERIT' + base_url + if use_inherit_extension: + base_url = '/OS-INHERIT' + base_url if user: params['user_id'] = base.getid(user) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/tokens.py python-keystoneclient-1.7.1/keystoneclient/v3/tokens.py --- python-keystoneclient-1.6.0/keystoneclient/v3/tokens.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/tokens.py 2015-09-09 04:34:24.000000000 +0000 @@ -52,6 +52,25 @@ return body @utils.positional.method(1) + def get_token_data(self, token, include_catalog=True): + """Fetch the data about a token from the identity server. + + :param str token: The token id. + :param bool include_catalog: If False, the response is requested to not + include the catalog. + + :rtype: dict + """ + headers = {'X-Subject-Token': token} + + url = '/auth/tokens' + if not include_catalog: + url += '?nocatalog' + + resp, body = self._client.get(url, headers=headers) + return body + + @utils.positional.method(1) def validate(self, token, include_catalog=True): """Validate a token. @@ -66,13 +85,5 @@ """ token_id = _calc_id(token) - headers = {'X-Subject-Token': token_id} - - url = '/auth/tokens' - if not include_catalog: - url += '?nocatalog' - - resp, body = self._client.get(url, headers=headers) - - access_info = access.AccessInfo.factory(resp=resp, body=body) - return access_info + body = self.get_token_data(token_id, include_catalog=include_catalog) + return access.AccessInfo.factory(auth_token=token_id, body=body) diff -Nru python-keystoneclient-1.6.0/keystoneclient/v3/users.py python-keystoneclient-1.7.1/keystoneclient/v3/users.py --- python-keystoneclient-1.6.0/keystoneclient/v3/users.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/keystoneclient/v3/users.py 2015-09-09 04:34:24.000000000 +0000 @@ -16,9 +16,11 @@ import logging +from debtcollector import renames + from keystoneclient import base from keystoneclient import exceptions -from keystoneclient.i18n import _, _LW +from keystoneclient.i18n import _ from keystoneclient import utils LOG = logging.getLogger(__name__) @@ -45,6 +47,8 @@ msg = _('Specify both a user and a group') raise exceptions.ValidationError(msg) + @renames.renamed_kwarg('project', 'default_project', version='1.7.0', + removal_version='2.0.0') @utils.positional(1, enforcement=utils.positional.WARN) def create(self, name, domain=None, project=None, password=None, email=None, description=None, enabled=True, @@ -53,14 +57,12 @@ .. warning:: - The project argument is deprecated, use default_project instead. + The project argument is deprecated as of the 1.7.0 release in favor + of default_project and may be removed in the 2.0.0 release. If both default_project and project is provided, the default_project will be used. """ - if project: - LOG.warning(_LW("The project argument is deprecated, " - "use default_project instead.")) default_project_id = base.getid(default_project) or base.getid(project) user_data = base.filter_none(name=name, domain_id=base.getid(domain), @@ -74,6 +76,8 @@ return self._create('/users', {'user': user_data}, 'user', log=not bool(password)) + @renames.renamed_kwarg('project', 'default_project', version='1.7.0', + removal_version='2.0.0') @utils.positional(enforcement=utils.positional.WARN) def list(self, project=None, domain=None, group=None, default_project=None, **kwargs): @@ -87,14 +91,12 @@ .. warning:: - The project argument is deprecated, use default_project instead. + The project argument is deprecated as of the 1.7.0 release in favor + of default_project and may be removed in the 2.0.0 release. If both default_project and project is provided, the default_project will be used. """ - if project: - LOG.warning(_LW("The project argument is deprecated, " - "use default_project instead.")) default_project_id = base.getid(default_project) or base.getid(project) if group: base_url = '/groups/%s' % base.getid(group) @@ -111,6 +113,8 @@ return super(UserManager, self).get( user_id=base.getid(user)) + @renames.renamed_kwarg('project', 'default_project', version='1.7.0', + removal_version='2.0.0') @utils.positional(enforcement=utils.positional.WARN) def update(self, user, name=None, domain=None, project=None, password=None, email=None, description=None, enabled=None, @@ -119,14 +123,12 @@ .. warning:: - The project argument is deprecated, use default_project instead. + The project argument is deprecated as of the 1.7.0 release in favor + of default_project and may be removed in the 2.0.0 release. If both default_project and project is provided, the default_project will be used. """ - if project: - LOG.warning(_LW("The project argument is deprecated, " - "use default_project instead.")) default_project_id = base.getid(default_project) or base.getid(project) user_data = base.filter_none(name=name, domain_id=base.getid(domain), @@ -156,7 +158,7 @@ params = {'user': {'password': new_password, 'original_password': old_password}} - base_url = '/users/%s/password' % self.api.user_id + base_url = '/users/%s/password' % self.client.user_id return self._update(base_url, params, method='POST', log=False, endpoint_filter={'interface': 'public'}) diff -Nru python-keystoneclient-1.6.0/README.rst python-keystoneclient-1.7.1/README.rst --- python-keystoneclient-1.6.0/README.rst 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/README.rst 2015-09-09 04:34:24.000000000 +0000 @@ -1,18 +1,29 @@ Python bindings to the OpenStack Identity API (Keystone) ======================================================== -This is a client for the OpenStack Identity API, implemented by Keystone. -There's a Python API (the ``keystoneclient`` module), and a command-line script -(``keystone``). - -Development takes place via the usual OpenStack processes as outlined in the -`developer guide `_. The master -repository is in `Git `_. - -This code is a fork of Rackspace's python-novaclient which is in turn a fork of -`Jacobian's python-cloudservers -`_. ``python-keystoneclient`` -is licensed under the Apache License like the rest of OpenStack. +This is a client for the OpenStack Identity API, implemented by the Keystone +team; it contains a Python API (the ``keystoneclient`` module) for +OpenStack's Identity Service. For command line interface support, use +`OpenStackClient`_. + +* `PyPi`_ - package installation +* `Online Documentation`_ +* `Launchpad project`_ - release management +* `Blueprints`_ - feature specifications +* `Bugs`_ - issue tracking +* `Source`_ +* `Specs`_ +* `How to Contribute`_ + +.. _PyPi: https://pypi.python.org/pypi/python-keystoneclient +.. _Online Documentation: http://docs.openstack.org/developer/python-keystoneclient +.. _Launchpad project: https://launchpad.net/python-keystoneclient +.. _Blueprints: https://blueprints.launchpad.net/python-keystoneclient +.. _Bugs: https://bugs.launchpad.net/python-keystoneclient +.. _Source: https://git.openstack.org/cgit/openstack/python-keystoneclient +.. _OpenStackClient: https://pypi.python.org/pypi/python-openstackclient +.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html +.. _Specs: http://specs.openstack.org/openstack/keystone-specs/ .. contents:: Contents: :local: @@ -28,175 +39,3 @@ >>> keystone.tenants.list() >>> tenant = keystone.tenants.create(tenant_name="test", description="My new tenant!", enabled=True) >>> tenant.delete() - - -Command-line API ----------------- - -Installing this package gets you a shell command, ``keystone``, that you can -use to interact with OpenStack's Identity API. - -You'll need to provide your OpenStack tenant, username and password. You can do -this with the ``--os-tenant-name``, ``--os-username`` and ``--os-password`` -params, but it's easier to just set them as environment variables:: - - export OS_TENANT_NAME=project - export OS_USERNAME=user - export OS_PASSWORD=pass - -You will also need to define the authentication url with ``--os-auth-url`` and -the version of the API with ``--os-identity-api-version``. Or set them as an -environment variables as well:: - - export OS_AUTH_URL=http://example.com:5000/v2.0 - export OS_IDENTITY_API_VERSION=2.0 - -Alternatively, to bypass username/password authentication, you can provide a -pre-established token. In Keystone, this approach is necessary to bootstrap the -service with an administrative user, tenant & role (to do so, provide the -client with the value of your ``admin_token`` defined in ``keystone.conf`` in -addition to the URL of your admin API deployment, typically on port 35357):: - - export OS_SERVICE_TOKEN=thequickbrownfox-jumpsover-thelazydog - export OS_SERVICE_ENDPOINT=http://example.com:35357/v2.0 - -Since the Identity service can return multiple regions in the service catalog, -you can specify the one you want with ``--os-region-name`` (or ``export -OS_REGION_NAME``):: - - export OS_REGION_NAME=north - -.. WARNING:: - - If a region is not specified and multiple regions are returned by the - Identity service, the client may not access the same region consistently. - -If you need to connect to a server that is TLS-enabled (the auth URL begins -with 'https') and it uses a certificate from a private CA or a self-signed -certificate you will need to specify the path to an appropriate CA certificate -to use to validate the server certificate with ``--os-cacert`` or an -environment variable:: - - export OS_CACERT=/etc/ssl/my-root-cert.pem - -Certificate verification can be turned off using ``--insecure``. This should -be used with caution. - -You'll find complete documentation on the shell by running ``keystone help``:: - - usage: keystone [--version] [--timeout ] - [--os-username ] - [--os-password ] - [--os-tenant-name ] - [--os-tenant-id ] [--os-auth-url ] - [--os-region-name ] - [--os-identity-api-version ] - [--os-token ] - [--os-endpoint ] - [--os-cacert ] [--insecure] - [--os-cert ] [--os-key ] [--os-cache] - [--force-new-token] [--stale-duration ] - ... - - Command-line interface to the OpenStack Identity API. - - Positional arguments: - - catalog - ec2-credentials-create - Create EC2-compatible credentials for user per tenant - ec2-credentials-delete - Delete EC2-compatible credentials - ec2-credentials-get - Display EC2-compatible credentials - ec2-credentials-list - List EC2-compatible credentials for a user - endpoint-create Create a new endpoint associated with a service - endpoint-delete Delete a service endpoint - endpoint-get - endpoint-list List configured service endpoints - password-update Update own password - role-create Create new role - role-delete Delete role - role-get Display role details - role-list List all roles - service-create Add service to Service Catalog - service-delete Delete service from Service Catalog - service-get Display service from Service Catalog - service-list List all services in Service Catalog - tenant-create Create new tenant - tenant-delete Delete tenant - tenant-get Display tenant details - tenant-list List all tenants - tenant-update Update tenant name, description, enabled status - token-get - user-create Create new user - user-delete Delete user - user-get Display user details. - user-list List users - user-password-update - Update user password - user-role-add Add role to user - user-role-list List roles granted to a user - user-role-remove Remove role from user - user-update Update user's name, email, and enabled status - discover Discover Keystone servers, supported API versions and - extensions. - bootstrap Grants a new role to a new user on a new tenant, after - creating each. - bash-completion Prints all of the commands and options to stdout. - help Display help about this program or one of its - subcommands. - - Optional arguments: - --version Shows the client version and exits - --timeout Set request timeout (in seconds) - --os-username - Name used for authentication with the OpenStack - Identity service. Defaults to env[OS_USERNAME] - --os-password - Password used for authentication with the OpenStack - Identity service. Defaults to env[OS_PASSWORD] - --os-tenant-name - Tenant to request authorization on. Defaults to - env[OS_TENANT_NAME] - --os-tenant-id - Tenant to request authorization on. Defaults to - env[OS_TENANT_ID] - --os-auth-url - Specify the Identity endpoint to use for - authentication. Defaults to env[OS_AUTH_URL] - --os-region-name - Defaults to env[OS_REGION_NAME] - --os-identity-api-version - Defaults to env[OS_IDENTITY_API_VERSION] or 2.0 - --os-token - Specify an existing token to use instead of retrieving - one via authentication (e.g. with username & - password). Defaults to env[OS_SERVICE_TOKEN] - --os-endpoint - Specify an endpoint to use instead of retrieving one - from the service catalog (via authentication). - Defaults to env[OS_SERVICE_ENDPOINT] - --os-cacert - Specify a CA bundle file to use in verifying a TLS - (https) server certificate. Defaults to env[OS_CACERT] - --insecure Explicitly allow keystoneclient to perform "insecure" - TLS (https) requests. The server's certificate will - not be verified against any certificate authorities. - This option should be used with caution. - --os-cert - Defaults to env[OS_CERT] - --os-key Defaults to env[OS_KEY] - --os-cache Use the auth token cache. Defaults to env[OS_CACHE] - --force-new-token If the keyring is available and in use, token will - always be stored and fetched from the keyring until - the token has expired. Use this option to request a - new token and replace the existing one in the keyring. - --stale-duration - Stale duration (in seconds) used to determine whether - a token has expired when retrieving it from keyring. - This is useful in mitigating process or network - delays. Default is 30 seconds. - - See "keystone help COMMAND" for help on a specific command. diff -Nru python-keystoneclient-1.6.0/requirements.txt python-keystoneclient-1.7.1/requirements.txt --- python-keystoneclient-1.6.0/requirements.txt 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/requirements.txt 2015-09-09 04:34:24.000000000 +0000 @@ -2,17 +2,18 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=0.11,<2.0 +pbr<2.0,>=1.6 argparse Babel>=1.3 iso8601>=0.1.9 -netaddr>=0.7.12 -oslo.config>=1.11.0 # Apache-2.0 -oslo.i18n>=1.5.0 # Apache-2.0 -oslo.serialization>=1.4.0 # Apache-2.0 -oslo.utils>=1.4.0 # Apache-2.0 -PrettyTable>=0.7,<0.8 +debtcollector>=0.3.0 # Apache-2.0 +netaddr!=0.7.16,>=0.7.12 +oslo.config>=2.3.0 # Apache-2.0 +oslo.i18n>=1.5.0 # Apache-2.0 +oslo.serialization>=1.4.0 # Apache-2.0 +oslo.utils>=2.0.0 # Apache-2.0 +PrettyTable<0.8,>=0.7 requests>=2.5.2 six>=1.9.0 -stevedore>=1.3.0 # Apache-2.0 +stevedore>=1.5.0 # Apache-2.0 diff -Nru python-keystoneclient-1.6.0/setup.cfg python-keystoneclient-1.7.1/setup.cfg --- python-keystoneclient-1.6.0/setup.cfg 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/setup.cfg 2015-09-09 04:34:24.000000000 +0000 @@ -17,7 +17,7 @@ Programming Language :: Python :: 2.7 Programming Language :: Python :: 2.6 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.3 + Programming Language :: Python :: 3.4 [files] packages = @@ -30,10 +30,12 @@ keystoneclient.auth.plugin = password = keystoneclient.auth.identity.generic:Password token = keystoneclient.auth.identity.generic:Token + admin_token = keystoneclient.auth.token_endpoint:Token v2password = keystoneclient.auth.identity.v2:Password v2token = keystoneclient.auth.identity.v2:Token v3password = keystoneclient.auth.identity.v3:Password v3token = keystoneclient.auth.identity.v3:Token + v3oidcpassword = keystoneclient.contrib.auth.v3.oidc:OidcPassword v3unscopedsaml = keystoneclient.contrib.auth.v3.saml2:Saml2UnscopedToken v3scopedsaml = keystoneclient.contrib.auth.v3.saml2:Saml2ScopedToken v3unscopedadfs = keystoneclient.contrib.auth.v3.saml2:ADFSUnscopedToken diff -Nru python-keystoneclient-1.6.0/setup.py python-keystoneclient-1.7.1/setup.py --- python-keystoneclient-1.6.0/setup.py 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/setup.py 2015-09-09 04:34:24.000000000 +0000 @@ -1,4 +1,3 @@ -#!/usr/bin/env python # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,5 +25,5 @@ pass setuptools.setup( - setup_requires=['pbr'], + setup_requires=['pbr>=1.3'], pbr=True) diff -Nru python-keystoneclient-1.6.0/test-requirements.txt python-keystoneclient-1.7.1/test-requirements.txt --- python-keystoneclient-1.6.0/test-requirements.txt 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/test-requirements.txt 2015-09-09 04:34:24.000000000 +0000 @@ -2,23 +2,25 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking>=0.10.0,<0.11 +hacking<0.11,>=0.10.0 coverage>=3.6 discover -fixtures>=0.3.14 -keyring>=2.1,!=3.3 +fixtures>=1.3.1 +keyring!=3.3,>=2.1 lxml>=2.3 -mock>=1.0 -mox3>=0.7.0 +mock>=1.2 oauthlib>=0.6 -oslosphinx>=2.5.0 # Apache-2.0 -oslotest>=1.5.1 # Apache-2.0 +oslosphinx>=2.5.0 # Apache-2.0 +oslotest>=1.10.0 # Apache-2.0 pycrypto>=2.6 -requests-mock>=0.6.0 # Apache-2.0 -sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 -tempest-lib>=0.5.0 +requests-mock>=0.6.0 # Apache-2.0 +sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 +tempest-lib>=0.6.1 testrepository>=0.0.18 testresources>=0.2.4 -testtools>=0.9.36,!=1.2.0 +testtools>=1.4.0 WebOb>=1.2.3 + +# Bandit security code scanner +bandit>=0.13.2 diff -Nru python-keystoneclient-1.6.0/tox.ini python-keystoneclient-1.7.1/tox.ini --- python-keystoneclient-1.6.0/tox.ini 2015-06-02 00:30:41.000000000 +0000 +++ python-keystoneclient-1.7.1/tox.ini 2015-09-09 04:34:24.000000000 +0000 @@ -1,7 +1,7 @@ [tox] minversion = 1.6 skipsdist = True -envlist = py26,py27,py33,py34,pep8 +envlist = py26,py27,py34,pep8,bandit [testenv] usedevelop = True @@ -12,7 +12,7 @@ deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --testr-args='{posargs}' +commands = python setup.py testr --slowest --testr-args='{posargs}' [testenv:pep8] commands = @@ -34,6 +34,10 @@ setenv = OS_TEST_PATH=./keystoneclient/tests/functional passenv = OS_* +[testenv:bandit] +deps = -r{toxinidir}/test-requirements.txt +commands = bandit -c bandit.yaml -r keystoneclient -n5 -p keystone_conservative + [flake8] # H405: multi line docstring summary not separated with an empty line ignore = H405