Merge remote-tracking branch 'origin/master' into merge-branch
Conflicts: keystoneclient/exceptions.py keystoneclient/fixture/discovery.py keystoneclient/fixture/v2.py keystoneclient/fixture/v3.py keystoneclient/middleware/auth_token.py keystoneclient/middleware/s3_token.py keystoneclient/tests/unit/test_auth_token_middleware.py keystoneclient/tests/unit/test_memcache_crypt.py keystoneclient/tests/unit/test_s3_token_middleware.py requirements.txt test-requirements.txt Change-Id: Ib51acebaac7966bf37c1562fa15b9061df6a7aa5
This commit is contained in:
commit
4e498a54d0
203
README.rst
203
README.rst
|
@ -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``).
|
||||
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`_.
|
||||
|
||||
Development takes place via the usual OpenStack processes as outlined in the
|
||||
`developer guide <http://docs.openstack.org/infra/manual/developers.html>`_. The master
|
||||
repository is in `Git <http://git.openstack.org/cgit/openstack/python-keystoneclient>`_.
|
||||
* `PyPi`_ - package installation
|
||||
* `Online Documentation`_
|
||||
* `Launchpad project`_ - release management
|
||||
* `Blueprints`_ - feature specifications
|
||||
* `Bugs`_ - issue tracking
|
||||
* `Source`_
|
||||
* `Specs`_
|
||||
* `How to Contribute`_
|
||||
|
||||
This code is a fork of Rackspace's python-novaclient which is in turn a fork of
|
||||
`Jacobian's python-cloudservers
|
||||
<http://github.com/jacobian/python-cloudservers>`_. ``python-keystoneclient``
|
||||
is licensed under the Apache License like the rest of OpenStack.
|
||||
.. _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 @@ By way of a quick-start::
|
|||
>>> 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 <seconds>]
|
||||
[--os-username <auth-user-name>]
|
||||
[--os-password <auth-password>]
|
||||
[--os-tenant-name <auth-tenant-name>]
|
||||
[--os-tenant-id <tenant-id>] [--os-auth-url <auth-url>]
|
||||
[--os-region-name <region-name>]
|
||||
[--os-identity-api-version <identity-api-version>]
|
||||
[--os-token <service-token>]
|
||||
[--os-endpoint <service-endpoint>]
|
||||
[--os-cacert <ca-certificate>] [--insecure]
|
||||
[--os-cert <certificate>] [--os-key <key>] [--os-cache]
|
||||
[--force-new-token] [--stale-duration <seconds>]
|
||||
<subcommand> ...
|
||||
|
||||
Command-line interface to the OpenStack Identity API.
|
||||
|
||||
Positional arguments:
|
||||
<subcommand>
|
||||
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 <seconds> Set request timeout (in seconds)
|
||||
--os-username <auth-user-name>
|
||||
Name used for authentication with the OpenStack
|
||||
Identity service. Defaults to env[OS_USERNAME]
|
||||
--os-password <auth-password>
|
||||
Password used for authentication with the OpenStack
|
||||
Identity service. Defaults to env[OS_PASSWORD]
|
||||
--os-tenant-name <auth-tenant-name>
|
||||
Tenant to request authorization on. Defaults to
|
||||
env[OS_TENANT_NAME]
|
||||
--os-tenant-id <tenant-id>
|
||||
Tenant to request authorization on. Defaults to
|
||||
env[OS_TENANT_ID]
|
||||
--os-auth-url <auth-url>
|
||||
Specify the Identity endpoint to use for
|
||||
authentication. Defaults to env[OS_AUTH_URL]
|
||||
--os-region-name <region-name>
|
||||
Defaults to env[OS_REGION_NAME]
|
||||
--os-identity-api-version <identity-api-version>
|
||||
Defaults to env[OS_IDENTITY_API_VERSION] or 2.0
|
||||
--os-token <service-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 <service-endpoint>
|
||||
Specify an endpoint to use instead of retrieving one
|
||||
from the service catalog (via authentication).
|
||||
Defaults to env[OS_SERVICE_ENDPOINT]
|
||||
--os-cacert <ca-certificate>
|
||||
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 <certificate>
|
||||
Defaults to env[OS_CERT]
|
||||
--os-key <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 <seconds>
|
||||
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.
|
||||
|
|
|
@ -103,7 +103,7 @@ add_module_names = True
|
|||
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'
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.27.20101213.0545 (20101213.0545)
|
||||
-->
|
||||
<!-- Title: AuthComp Pages: 1 -->
|
||||
<svg width="510pt" height="118pt"
|
||||
viewBox="0.00 0.00 510.00 118.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 114)">
|
||||
<title>AuthComp</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-114 507,-114 507,5 -4,5"/>
|
||||
<!-- AuthComp -->
|
||||
<g id="node2" class="node"><title>AuthComp</title>
|
||||
<polygon fill="#fdefe3" stroke="#c00000" points="292,-65 194,-65 194,-25 292,-25 292,-65"/>
|
||||
<text text-anchor="middle" x="243" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">Auth</text>
|
||||
<text text-anchor="middle" x="243" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Component</text>
|
||||
</g>
|
||||
<!-- Reject -->
|
||||
<!-- AuthComp->Reject -->
|
||||
<g id="edge3" class="edge"><title>AuthComp->Reject</title>
|
||||
<path fill="none" stroke="black" d="M193.933,-51.2787C157.514,-55.939 108.38,-62.2263 73.8172,-66.649"/>
|
||||
<polygon fill="black" stroke="black" points="73.0637,-63.2168 63.5888,-67.9578 73.9522,-70.1602 73.0637,-63.2168"/>
|
||||
<text text-anchor="middle" x="129" y="-97.4" font-family="Times,serif" font-size="14.00">Reject</text>
|
||||
<text text-anchor="middle" x="129" y="-82.4" font-family="Times,serif" font-size="14.00">Unauthenticated</text>
|
||||
<text text-anchor="middle" x="129" y="-67.4" font-family="Times,serif" font-size="14.00">Requests</text>
|
||||
</g>
|
||||
<!-- Service -->
|
||||
<g id="node6" class="node"><title>Service</title>
|
||||
<polygon fill="#d1ebf1" stroke="#1f477d" points="502,-65 408,-65 408,-25 502,-25 502,-65"/>
|
||||
<text text-anchor="middle" x="455" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">OpenStack</text>
|
||||
<text text-anchor="middle" x="455" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Service</text>
|
||||
</g>
|
||||
<!-- AuthComp->Service -->
|
||||
<g id="edge5" class="edge"><title>AuthComp->Service</title>
|
||||
<path fill="none" stroke="black" d="M292.17,-45C323.626,-45 364.563,-45 397.52,-45"/>
|
||||
<polygon fill="black" stroke="black" points="397.917,-48.5001 407.917,-45 397.917,-41.5001 397.917,-48.5001"/>
|
||||
<text text-anchor="middle" x="350" y="-77.4" font-family="Times,serif" font-size="14.00">Forward</text>
|
||||
<text text-anchor="middle" x="350" y="-62.4" font-family="Times,serif" font-size="14.00">Authenticated</text>
|
||||
<text text-anchor="middle" x="350" y="-47.4" font-family="Times,serif" font-size="14.00">Requests</text>
|
||||
</g>
|
||||
<!-- Start -->
|
||||
<!-- Start->AuthComp -->
|
||||
<g id="edge7" class="edge"><title>Start->AuthComp</title>
|
||||
<path fill="none" stroke="black" d="M59.1526,-21.4745C90.4482,-25.4792 142.816,-32.1802 183.673,-37.4084"/>
|
||||
<polygon fill="black" stroke="black" points="183.43,-40.9057 193.793,-38.7034 184.318,-33.9623 183.43,-40.9057"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.9 KiB |
|
@ -1,53 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.27.20101213.0545 (20101213.0545)
|
||||
-->
|
||||
<!-- Title: AuthCompDelegate Pages: 1 -->
|
||||
<svg width="588pt" height="104pt"
|
||||
viewBox="0.00 0.00 588.00 104.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 100)">
|
||||
<title>AuthCompDelegate</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-100 585,-100 585,5 -4,5"/>
|
||||
<!-- AuthComp -->
|
||||
<g id="node2" class="node"><title>AuthComp</title>
|
||||
<polygon fill="#fdefe3" stroke="#c00000" points="338,-65 240,-65 240,-25 338,-25 338,-65"/>
|
||||
<text text-anchor="middle" x="289" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">Auth</text>
|
||||
<text text-anchor="middle" x="289" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Component</text>
|
||||
</g>
|
||||
<!-- Reject -->
|
||||
<!-- AuthComp->Reject -->
|
||||
<g id="edge3" class="edge"><title>AuthComp->Reject</title>
|
||||
<path fill="none" stroke="black" d="M239.6,-50.1899C191.406,-55.2531 118.917,-62.8686 73.5875,-67.6309"/>
|
||||
<polygon fill="black" stroke="black" points="73.0928,-64.1635 63.5132,-68.6893 73.8242,-71.1252 73.0928,-64.1635"/>
|
||||
<text text-anchor="middle" x="152" y="-83.4" font-family="Times,serif" font-size="14.00">Reject Requests</text>
|
||||
<text text-anchor="middle" x="152" y="-68.4" font-family="Times,serif" font-size="14.00">Indicated by the Service</text>
|
||||
</g>
|
||||
<!-- Service -->
|
||||
<g id="node6" class="node"><title>Service</title>
|
||||
<polygon fill="#d1ebf1" stroke="#1f477d" points="580,-65 486,-65 486,-25 580,-25 580,-65"/>
|
||||
<text text-anchor="middle" x="533" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">OpenStack</text>
|
||||
<text text-anchor="middle" x="533" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Service</text>
|
||||
</g>
|
||||
<!-- AuthComp->Service -->
|
||||
<g id="edge5" class="edge"><title>AuthComp->Service</title>
|
||||
<path fill="none" stroke="black" d="M338.009,-49.0804C344.065,-49.4598 350.172,-49.7828 356,-50 405.743,-51.8535 418.259,-51.9103 468,-50 470.523,-49.9031 473.101,-49.7851 475.704,-49.6504"/>
|
||||
<polygon fill="black" stroke="black" points="476.03,-53.1374 485.807,-49.0576 475.62,-46.1494 476.03,-53.1374"/>
|
||||
<text text-anchor="middle" x="412" y="-68.4" font-family="Times,serif" font-size="14.00">Forward Requests</text>
|
||||
<text text-anchor="middle" x="412" y="-53.4" font-family="Times,serif" font-size="14.00">with Identiy Status</text>
|
||||
</g>
|
||||
<!-- Service->AuthComp -->
|
||||
<g id="edge7" class="edge"><title>Service->AuthComp</title>
|
||||
<path fill="none" stroke="black" d="M495.062,-24.9037C486.397,-21.2187 477.064,-17.9304 468,-16 419.314,-5.63183 404.743,-5.9037 356,-16 349.891,-17.2653 343.655,-19.116 337.566,-21.2803"/>
|
||||
<polygon fill="black" stroke="black" points="336.234,-18.0426 328.158,-24.9003 338.748,-24.5757 336.234,-18.0426"/>
|
||||
<text text-anchor="middle" x="412" y="-33.4" font-family="Times,serif" font-size="14.00">Send Response OR</text>
|
||||
<text text-anchor="middle" x="412" y="-18.4" font-family="Times,serif" font-size="14.00">Reject Message</text>
|
||||
</g>
|
||||
<!-- Start -->
|
||||
<!-- Start->AuthComp -->
|
||||
<g id="edge9" class="edge"><title>Start->AuthComp</title>
|
||||
<path fill="none" stroke="black" d="M59.0178,-20.8384C99.2135,-25.0613 175.782,-33.1055 229.492,-38.7482"/>
|
||||
<polygon fill="black" stroke="black" points="229.265,-42.2435 239.576,-39.8076 229.997,-35.2818 229.265,-42.2435"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.5 KiB |
|
@ -195,6 +195,9 @@ class Discover(object):
|
|||
: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 = []
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
|
||||
import datetime
|
||||
import warnings
|
||||
|
||||
from oslo_utils import timeutils
|
||||
|
||||
|
@ -39,9 +40,20 @@ class AccessInfo(dict):
|
|||
**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 @@ class AccessInfo(dict):
|
|||
"""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 @@ class AccessInfo(dict):
|
|||
(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 @@ class AccessInfo(dict):
|
|||
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 @@ class AccessInfoV2(AccessInfo):
|
|||
|
||||
@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 @@ class AccessInfoV2(AccessInfo):
|
|||
|
||||
@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 @@ class AccessInfoV2(AccessInfo):
|
|||
|
||||
@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 @@ class AccessInfoV3(AccessInfo):
|
|||
|
||||
@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 @@ class AccessInfoV3(AccessInfo):
|
|||
|
||||
@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 @@ class AccessInfoV3(AccessInfo):
|
|||
|
||||
@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',
|
||||
|
|
|
@ -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 @@ from keystoneclient import exceptions
|
|||
# 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',
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import abc
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
|
@ -54,12 +55,106 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
|
|||
|
||||
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):
|
||||
|
|
|
@ -72,6 +72,16 @@ class BaseGenericPlugin(base.BaseIdentityPlugin):
|
|||
|
||||
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.
|
||||
|
|
|
@ -57,10 +57,20 @@ class Auth(base.BaseIdentityPlugin):
|
|||
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 @@ class Password(Auth):
|
|||
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 @@ class Token(Auth):
|
|||
|
||||
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:
|
||||
|
|
|
@ -59,7 +59,7 @@ class BaseAuth(base.BaseIdentityPlugin):
|
|||
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
|
||||
|
@ -68,6 +68,16 @@ class BaseAuth(base.BaseIdentityPlugin):
|
|||
self.project_domain_name = project_domain_name
|
||||
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."""
|
||||
|
|
|
@ -20,15 +20,17 @@ Base utilities to build API operation managers and objects on top of.
|
|||
"""
|
||||
|
||||
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 @@ class Manager(object):
|
|||
|
||||
@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 @@ class CrudManager(Manager):
|
|||
|
||||
@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 @@ class CrudManager(Manager):
|
|||
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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -26,10 +26,11 @@ import logging
|
|||
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
|
||||
|
@ -297,10 +298,14 @@ def is_asn1_token(token):
|
|||
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)
|
||||
|
||||
|
||||
|
|
|
@ -87,14 +87,34 @@ class OidcPassword(federated.FederatedBaseAuth):
|
|||
"""
|
||||
super(OidcPassword, self).__init__(auth_url, identity_provider,
|
||||
protocol)
|
||||
self.username = username
|
||||
self.password = password
|
||||
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.
|
||||
|
||||
|
|
|
@ -170,7 +170,27 @@ class Saml2UnscopedToken(_BaseSAMLPlugin):
|
|||
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 @@ class ADFSUnscopedToken(_BaseSAMLPlugin):
|
|||
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):
|
||||
|
|
|
@ -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 @@ class RevokeEvent(object):
|
|||
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):
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import logging
|
||||
|
||||
from debtcollector import removals
|
||||
import six
|
||||
|
||||
from keystoneclient import _discover
|
||||
|
@ -165,14 +166,19 @@ class Discover(_discover.Discover):
|
|||
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 +191,10 @@ class Discover(_discover.Discover):
|
|||
"""
|
||||
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 +202,10 @@ class Discover(_discover.Discover):
|
|||
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.
|
||||
|
|
|
@ -12,20 +12,7 @@
|
|||
# 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.
|
||||
|
||||
.. py:exception:: AuthorizationFailure
|
||||
|
||||
.. py:exception:: ClientException
|
||||
|
||||
.. py:exception:: HttpError
|
||||
|
||||
.. py:exception:: ValidationError
|
||||
|
||||
.. py:exception:: Unauthorized
|
||||
|
||||
"""
|
||||
"""Exception definitions."""
|
||||
|
||||
from keystoneauth1 import exceptions as new_exceptions
|
||||
|
||||
|
@ -68,7 +55,6 @@ GatewayTimeout = new_exceptions.GatewayTimeout
|
|||
HttpVersionNotSupported = new_exceptions.HttpVersionNotSupported
|
||||
from_response = new_exceptions.from_response
|
||||
|
||||
|
||||
# NOTE(jamielennox): Rahh! this is just wrong. In the apiclient conversion
|
||||
# someone mapped the connection timeout onto the HTTP timeout exception. Assume
|
||||
# people want the connection timeout as this is much more common.
|
||||
|
@ -82,9 +68,7 @@ Timeout = new_exceptions.ConnectTimeout
|
|||
# NOTE(akurilin): This alias should be left here to support backwards
|
||||
# compatibility until we are sure that usage of these exceptions in
|
||||
# projects is correct.
|
||||
ConnectionRefused = ConnectionError
|
||||
HTTPNotImplemented = HttpNotImplemented
|
||||
Timeout = RequestTimeout
|
||||
HTTPError = HttpError
|
||||
|
||||
|
||||
|
@ -105,19 +89,27 @@ class MultipleChoices(HTTPRedirection):
|
|||
|
||||
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
|
||||
|
||||
|
||||
AuthorizationFailure = new_exceptions.AuthorizationFailure
|
||||
|
||||
|
||||
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):
|
||||
|
@ -131,7 +123,7 @@ class AuthSystemNotFound(AuthorizationFailure):
|
|||
"""User has specified an AuthSystem that is not installed."""
|
||||
def __init__(self, auth_system):
|
||||
super(AuthSystemNotFound, self).__init__(
|
||||
_("AuthSystemNotFound: %s") % repr(auth_system))
|
||||
_("AuthSystemNotFound: %r") % auth_system)
|
||||
self.auth_system = auth_system
|
||||
|
||||
|
||||
|
@ -165,7 +157,7 @@ class AmbiguousEndpoints(EndpointException):
|
|||
"""Found more than one matching endpoint in Service Catalog."""
|
||||
def __init__(self, endpoints=None):
|
||||
super(AmbiguousEndpoints, self).__init__(
|
||||
_("AmbiguousEndpoints: %s") % repr(endpoints))
|
||||
_("AmbiguousEndpoints: %r") % endpoints)
|
||||
self.endpoints = endpoints
|
||||
|
||||
|
||||
|
|
|
@ -84,9 +84,9 @@ class Client(httpclient.HTTPClient):
|
|||
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 @@ class Client(httpclient.HTTPClient):
|
|||
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)
|
||||
|
|
|
@ -20,7 +20,10 @@ OpenStack Client interface. Handles the REST calls and responses.
|
|||
"""
|
||||
|
||||
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,21 @@ from keystoneclient import utils
|
|||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# These variables are moved and using them via httpclient is deprecated.
|
||||
# This variable is moved and using it via httpclient is deprecated.
|
||||
# Maintain here for compatibility.
|
||||
USER_AGENT = client_session.USER_AGENT
|
||||
request = client_session.request
|
||||
|
||||
|
||||
@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):
|
||||
|
@ -178,10 +192,13 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +221,10 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
|
||||
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,8 +269,14 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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
|
||||
if self.auth_ref.has_service_catalog() and not region_name:
|
||||
|
@ -398,15 +425,35 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
@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)
|
||||
|
@ -649,6 +696,7 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +704,15 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +721,14 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +736,16 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +753,16 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +770,16 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +787,16 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +804,16 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +821,15 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +838,15 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +854,24 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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 +879,10 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
|||
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)
|
||||
|
|
|
@ -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')
|
|
@ -33,18 +33,22 @@ Base utilities to build API operation managers and objects on top of.
|
|||
#
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# 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 @@ class Extension(HookableMixin):
|
|||
return "<Extension '%s'>" % 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
|
||||
|
|
|
@ -33,447 +33,61 @@ Exception definitions.
|
|||
#
|
||||
########################################################################
|
||||
|
||||
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 _
|
||||
|
||||
|
||||
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', '')
|
||||
|
||||
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 import exceptions
|
||||
|
||||
|
||||
"""Exception definitions."""
|
||||
|
||||
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
|
||||
|
|
|
@ -899,11 +899,37 @@ class Session(object):
|
|||
|
||||
|
||||
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),
|
||||
])
|
||||
# Set the maximum number of keep-alive probes
|
||||
(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4),
|
||||
# Send keep-alive probes every 15 seconds
|
||||
(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15),
|
||||
]
|
||||
|
||||
# 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)
|
||||
]
|
||||
|
||||
# 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)
|
||||
|
|
|
@ -512,7 +512,8 @@ class V3IdentityPlugin(utils.TestCase):
|
|||
|
||||
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']
|
||||
|
|
|
@ -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 @@ class HackingCode(fixtures.Fixture):
|
|||
(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\\.')
|
||||
|
|
|
@ -36,9 +36,7 @@ class BaseTest(utils.TestCase):
|
|||
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,
|
||||
self.client = client.Client(token=self.TEST_TOKEN,
|
||||
auth_url='http://127.0.0.1:5000',
|
||||
endpoint='http://127.0.0.1:5000')
|
||||
|
||||
|
@ -85,16 +83,15 @@ class ManagerTest(utils.TestCase):
|
|||
|
||||
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,
|
||||
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):
|
||||
get_mock = self.useFixture(mockpatch.PatchObject(
|
||||
|
|
|
@ -472,7 +472,8 @@ class ClientDiscoveryTests(utils.TestCase):
|
|||
|
||||
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)
|
||||
|
||||
|
@ -499,7 +500,8 @@ class ClientDiscoveryTests(utils.TestCase):
|
|||
text=V3_VERSION_ENTRY)
|
||||
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])
|
||||
|
||||
|
|
|
@ -17,12 +17,14 @@ from __future__ import unicode_literals
|
|||
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)
|
||||
|
|
|
@ -21,6 +21,9 @@ from keystoneclient.tests.unit import client_fixtures
|
|||
|
||||
|
||||
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.
|
||||
|
|
|
@ -28,7 +28,7 @@ RESPONSE_BODY = '{"hi": "there"}'
|
|||
|
||||
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
|
||||
|
||||
|
||||
|
@ -67,7 +67,8 @@ class ClientTest(utils.TestCase):
|
|||
|
||||
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)
|
||||
|
||||
|
@ -96,7 +97,8 @@ class ClientTest(utils.TestCase):
|
|||
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")
|
||||
|
@ -106,7 +108,8 @@ class ClientTest(utils.TestCase):
|
|||
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]')
|
||||
|
@ -118,12 +121,13 @@ class ClientTest(utils.TestCase):
|
|||
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",
|
||||
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 +171,8 @@ class BasicRequestTests(utils.TestCase):
|
|||
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'
|
||||
|
|
|
@ -28,7 +28,7 @@ RESPONSE_BODY = b'{"hi": "there"}'
|
|||
|
||||
def get_client():
|
||||
cl = httpclient.HTTPClient(username="username", password="password",
|
||||
tenant_id="tenant", auth_url="auth_test",
|
||||
project_id="tenant", auth_url="auth_test",
|
||||
cacert="ca.pem", key="key.pem", cert="cert.pem")
|
||||
return cl
|
||||
|
||||
|
@ -47,7 +47,8 @@ class ClientTest(utils.TestCase):
|
|||
MOCK_REQUEST.return_value = FAKE_RESPONSE
|
||||
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
|
||||
|
@ -66,7 +67,8 @@ class ClientTest(utils.TestCase):
|
|||
MOCK_REQUEST.return_value = FAKE_RESPONSE
|
||||
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
|
||||
|
@ -82,12 +84,13 @@ class ClientTest(utils.TestCase):
|
|||
def test_post_auth(self, MOCK_REQUEST):
|
||||
MOCK_REQUEST.return_value = FAKE_RESPONSE
|
||||
cl = httpclient.HTTPClient(
|
||||
username="username", password="password", tenant_id="tenant",
|
||||
username="username", password="password", project_id="tenant",
|
||||
auth_url="auth_test", cacert="ca.pem", key="key.pem",
|
||||
cert="cert.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
|
||||
|
|
|
@ -19,6 +19,7 @@ from keystoneclient import access
|
|||
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
|
||||
|
@ -87,7 +88,7 @@ class KeyringTest(utils.TestCase):
|
|||
the keyring is never accessed.
|
||||
"""
|
||||
cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD,
|
||||
tenant_id=TENANT_ID, auth_url=AUTH_URL)
|
||||
project_id=TENANT_ID, auth_url=AUTH_URL)
|
||||
|
||||
# stub and check that a new token is received
|
||||
method = 'get_raw_token_from_identity_service'
|
||||
|
@ -104,7 +105,7 @@ class KeyringTest(utils.TestCase):
|
|||
|
||||
def test_build_keyring_key(self):
|
||||
cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD,
|
||||
tenant_id=TENANT_ID, auth_url=AUTH_URL)
|
||||
project_id=TENANT_ID, auth_url=AUTH_URL)
|
||||
|
||||
keyring_key = cl._build_keyring_key(auth_url=AUTH_URL,
|
||||
username=USERNAME,
|
||||
|
@ -118,13 +119,13 @@ class KeyringTest(utils.TestCase):
|
|||
|
||||
def test_set_and_get_keyring_expired(self):
|
||||
cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD,
|
||||
tenant_id=TENANT_ID, auth_url=AUTH_URL,
|
||||
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
|
||||
|
@ -146,13 +147,13 @@ class KeyringTest(utils.TestCase):
|
|||
|
||||
def test_get_keyring(self):
|
||||
cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD,
|
||||
tenant_id=TENANT_ID, auth_url=AUTH_URL,
|
||||
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
|
||||
|
@ -162,7 +163,7 @@ class KeyringTest(utils.TestCase):
|
|||
|
||||
def test_set_keyring(self):
|
||||
cl = httpclient.HTTPClient(username=USERNAME, password=PASSWORD,
|
||||
tenant_id=TENANT_ID, auth_url=AUTH_URL,
|
||||
project_id=TENANT_ID, auth_url=AUTH_URL,
|
||||
use_keyring=True)
|
||||
|
||||
# stub and check that a new token is received
|
||||
|
|
|
@ -12,18 +12,18 @@
|
|||
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import fixtures
|
||||
from oslo_serialization import jsonutils
|
||||
from oslotest import mockpatch
|
||||
import requests
|
||||
from requests_mock.contrib import fixture
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import testtools
|
||||
|
||||
from keystoneclient.tests.unit import client_fixtures
|
||||
|
||||
|
||||
class TestCase(testtools.TestCase):
|
||||
|
||||
|
@ -42,10 +42,9 @@ class TestCase(testtools.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
super(TestCase, self).setUp()
|
||||
self.logger = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
||||
self.time_patcher = self.useFixture(
|
||||
mockpatch.PatchObject(time, 'time', lambda: 1234)).mock
|
||||
self.deprecations = self.useFixture(client_fixtures.Deprecations())
|
||||
|
||||
self.logger = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
||||
self.requests_mock = self.useFixture(fixture.Fixture())
|
||||
|
||||
def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs):
|
||||
|
|
|
@ -45,10 +45,13 @@ class AccessInfoTest(utils.TestCase, testresources.ResourcedTestCase):
|
|||
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 @@ class AccessInfoTest(utils.TestCase, testresources.ResourcedTestCase):
|
|||
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 @@ class AccessInfoTest(utils.TestCase, testresources.ResourcedTestCase):
|
|||
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[
|
||||
|
|
|
@ -67,7 +67,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
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)
|
||||
|
@ -95,7 +95,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
def client_create_wrapper():
|
||||
client.Client(username=self.TEST_USER,
|
||||
password="bad_key",
|
||||
tenant_id=self.TEST_TENANT_ID,
|
||||
project_id=self.TEST_TENANT_ID,
|
||||
auth_url=self.TEST_URL)
|
||||
|
||||
self.assertRaises(exceptions.Unauthorized, client_create_wrapper)
|
||||
|
@ -110,7 +110,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
|
||||
cs = client.Client(username=self.TEST_USER,
|
||||
password=self.TEST_TOKEN,
|
||||
tenant_id=self.TEST_TENANT_ID,
|
||||
project_id=self.TEST_TENANT_ID,
|
||||
auth_url=self.TEST_URL)
|
||||
|
||||
self.assertEqual(cs.management_url,
|
||||
|
@ -125,7 +125,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
|
||||
cs = client.Client(username=self.TEST_USER,
|
||||
password=self.TEST_TOKEN,
|
||||
tenant_id=self.TEST_TENANT_ID,
|
||||
project_id=self.TEST_TENANT_ID,
|
||||
auth_url=self.TEST_URL)
|
||||
self.assertEqual(cs.management_url,
|
||||
self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3]
|
||||
|
@ -162,7 +162,8 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
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')
|
||||
|
@ -174,7 +175,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
|
||||
cs = client.Client(token=self.TEST_TOKEN,
|
||||
tenant_id=self.TEST_TENANT_ID,
|
||||
project_id=self.TEST_TENANT_ID,
|
||||
auth_url=self.TEST_URL)
|
||||
self.assertEqual(cs.management_url,
|
||||
self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3]
|
||||
|
@ -193,7 +194,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
self.stub_auth(json=response)
|
||||
|
||||
cs = client.Client(token=self.TEST_TOKEN,
|
||||
tenant_id=self.TEST_TENANT_ID,
|
||||
project_id=self.TEST_TENANT_ID,
|
||||
trust_id=self.TEST_TRUST_ID,
|
||||
auth_url=self.TEST_URL)
|
||||
self.assertTrue(cs.auth_ref.trust_scoped)
|
||||
|
@ -227,13 +228,14 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
|
||||
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')
|
||||
|
@ -242,7 +244,8 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
# 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 +254,8 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
# 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')
|
||||
|
|
|
@ -34,7 +34,8 @@ class KeystoneClientTest(utils.TestCase):
|
|||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
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):
|
||||
|
|
|
@ -168,6 +168,9 @@ class TokenTests(utils.TestCase):
|
|||
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 @@ class TokenTests(utils.TestCase):
|
|||
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_)
|
||||
|
||||
|
|
|
@ -78,9 +78,7 @@ class TestCase(UnauthenticatedTestCase):
|
|||
|
||||
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,
|
||||
self.client = client.Client(token=self.TEST_TOKEN,
|
||||
auth_url=self.TEST_URL,
|
||||
endpoint=self.TEST_URL)
|
||||
|
||||
|
|
|
@ -16,26 +16,18 @@ import uuid
|
|||
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 unscoped_token(**kwargs):
|
||||
return fixture.V3Token(**kwargs)
|
||||
|
||||
|
||||
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 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(id='76e72a', name='admin')
|
||||
f.add_role(id='f4f392', name='member')
|
||||
f.add_role(name='admin')
|
||||
f.add_role(name='member')
|
||||
region = 'RegionOne'
|
||||
|
||||
s = f.add_service('volume')
|
||||
|
@ -71,20 +63,15 @@ def domain_scoped_token():
|
|||
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 @@ def project_scoped_token():
|
|||
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 @@ AUTH_RESPONSE_HEADERS = {
|
|||
|
||||
|
||||
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 auth_response_body():
|
|||
|
||||
|
||||
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
|
||||
|
|
|
@ -38,10 +38,10 @@ class AccessInfoTest(utils.TestCase):
|
|||
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 @@ class AccessInfoTest(utils.TestCase):
|
|||
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 @@ class AccessInfoTest(utils.TestCase):
|
|||
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(DOMAIN_SCOPED_TOKEN.user_name, auth_ref.username)
|
||||
self.assertEqual(DOMAIN_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(DOMAIN_SCOPED_TOKEN.role_ids, auth_ref.role_ids)
|
||||
self.assertEqual(DOMAIN_SCOPED_TOKEN.role_names, auth_ref.role_names)
|
||||
|
||||
self.assertEqual(auth_ref.domain_name, 'anotherdomain')
|
||||
self.assertEqual(auth_ref.domain_id,
|
||||
'8e9283b7ba0b1038840c3842058b86ab')
|
||||
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 @@ class AccessInfoTest(utils.TestCase):
|
|||
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',))
|
||||
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(auth_ref.project_domain_id,
|
||||
'4e6893b7ba0b4006840c3845660b86ed')
|
||||
self.assertEqual(auth_ref.project_domain_name, 'exampledomain')
|
||||
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(auth_ref.user_domain_id,
|
||||
'4e6893b7ba0b4006840c3845660b86ed')
|
||||
self.assertEqual(auth_ref.user_domain_name, 'exampledomain')
|
||||
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)
|
||||
|
|
|
@ -229,7 +229,8 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
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 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
|
||||
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 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
# 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 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||
# 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')
|
||||
|
|
|
@ -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)
|
|
@ -27,71 +27,67 @@ from keystoneclient.v3 import client
|
|||
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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
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
|
||||
|
||||
c = client.Client(user_id='c4da488862bd435c9e6c0275a0d0e49a',
|
||||
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=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 @@ class KeystoneClientTest(utils.TestCase):
|
|||
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,
|
||||
|
@ -190,7 +196,7 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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 +204,7 @@ class KeystoneClientTest(utils.TestCase):
|
|||
|
||||
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'),
|
||||
|
|
|
@ -30,6 +30,12 @@ class DomainTests(utils.TestCase, utils.CrudTests):
|
|||
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')
|
||||
|
||||
|
|
|
@ -278,6 +278,16 @@ class ProtocolTests(utils.TestCase, utils.CrudTests):
|
|||
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}
|
||||
|
|
|
@ -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 testtools import matchers
|
|||
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 @@ class TokenTests(BaseTest):
|
|||
|
||||
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 @@ 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)
|
||||
|
||||
|
|
|
@ -71,6 +71,15 @@ class RoleAssignmentsTests(utils.TestCase, utils.CrudTests):
|
|||
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',
|
||||
|
|
|
@ -53,6 +53,10 @@ class TokenTests(utils.TestCase, testresources.ResourcedTestCase):
|
|||
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 @@ class TokenTests(utils.TestCase, testresources.ResourcedTestCase):
|
|||
# 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 @@ class TokenTests(utils.TestCase, testresources.ResourcedTestCase):
|
|||
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 @@ class TokenTests(utils.TestCase, testresources.ResourcedTestCase):
|
|||
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)
|
||||
|
||||
|
|
|
@ -129,9 +129,7 @@ class TestCase(UnauthenticatedTestCase):
|
|||
|
||||
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,
|
||||
self.client = client.Client(token=self.TEST_TOKEN,
|
||||
auth_url=self.TEST_URL,
|
||||
endpoint=self.TEST_URL)
|
||||
|
||||
|
@ -245,6 +243,20 @@ class CrudTests(object):
|
|||
|
||||
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()]
|
||||
|
|
|
@ -18,6 +18,7 @@ import logging
|
|||
import sys
|
||||
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import timeutils
|
||||
import prettytable
|
||||
import six
|
||||
|
||||
|
@ -336,3 +337,37 @@ class positional(object):
|
|||
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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -84,6 +84,17 @@ class TokenManager(base.Manager):
|
|||
"""
|
||||
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 @@ class TokenManager(base.Manager):
|
|||
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.
|
||||
|
|
|
@ -75,7 +75,8 @@ class UserManager(base.ManagerWithFind):
|
|||
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'},
|
||||
|
|
|
@ -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)
|
|
@ -21,6 +21,7 @@ from keystoneclient.auth.identity import v3 as v3_auth
|
|||
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 +66,13 @@ class Client(httpclient.HTTPClient):
|
|||
: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.
|
||||
|
@ -179,6 +182,7 @@ EndpointPolicyManager`
|
|||
"""Initialize a new client for the Keystone v3 API."""
|
||||
super(Client, self).__init__(**kwargs)
|
||||
|
||||
self.auth = auth.AuthManager(self._adapter)
|
||||
self.credentials = credentials.CredentialManager(self._adapter)
|
||||
self.ec2 = ec2.EC2Manager(self._adapter)
|
||||
self.endpoint_filter = endpoint_filter.EndpointFilterManager(
|
||||
|
|
|
@ -40,7 +40,8 @@ class AccessTokenManager(base.CrudManager):
|
|||
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)
|
||||
|
|
|
@ -63,7 +63,8 @@ class RequestTokenManager(base.CrudManager):
|
|||
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)
|
||||
|
|
|
@ -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 @@ class TrustManager(base.CrudManager):
|
|||
|
||||
# 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
|
||||
|
||||
|
|
|
@ -51,6 +51,25 @@ class TokenManager(object):
|
|||
resp, body = self._client.get('/auth/tokens/OS-PKI/revoked')
|
||||
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 @@ class TokenManager(object):
|
|||
"""
|
||||
|
||||
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)
|
||||
|
|
|
@ -156,7 +156,7 @@ class UserManager(base.CrudManager):
|
|||
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'})
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr<2.0,>=0.11
|
||||
pbr<2.0,>=1.3
|
||||
|
||||
argparse
|
||||
Babel>=1.3
|
||||
keystoneauth1 >= 0.3.0
|
||||
iso8601>=0.1.9
|
||||
debtcollector>=0.3.0 # Apache-2.0
|
||||
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.6.0 # Apache-2.0
|
||||
oslo.utils>=1.9.0 # Apache-2.0
|
||||
PrettyTable<0.8,>=0.7
|
||||
requests>=2.5.2
|
||||
six>=1.9.0
|
||||
|
|
|
@ -17,7 +17,7 @@ classifier =
|
|||
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 =
|
||||
|
|
2
setup.py
2
setup.py
|
@ -25,5 +25,5 @@ except ImportError:
|
|||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
setup_requires=['pbr>=1.3'],
|
||||
pbr=True)
|
||||
|
|
|
@ -6,17 +6,16 @@ hacking<0.11,>=0.10.0
|
|||
|
||||
coverage>=3.6
|
||||
discover
|
||||
fixtures>=0.3.14
|
||||
fixtures>=1.3.1
|
||||
keyring!=3.3,>=2.1
|
||||
lxml>=2.3
|
||||
mock>=1.1;python_version!='2.6'
|
||||
mock==1.0.1;python_version=='2.6'
|
||||
mock>=1.2
|
||||
oauthlib>=0.6
|
||||
oslosphinx>=2.5.0 # Apache-2.0
|
||||
oslotest>=1.5.1 # Apache-2.0
|
||||
oslotest>=1.10.0 # Apache-2.0
|
||||
requests-mock>=0.6.0 # Apache-2.0
|
||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||
tempest-lib>=0.5.0
|
||||
tempest-lib>=0.6.1
|
||||
testrepository>=0.0.18
|
||||
testresources>=0.2.4
|
||||
testtools>=1.4.0
|
||||
|
|
Loading…
Reference in New Issue