diff --git a/heatclient/common/http.py b/heatclient/common/http.py index 10072375..cbf4540a 100644 --- a/heatclient/common/http.py +++ b/heatclient/common/http.py @@ -216,12 +216,6 @@ class HTTPClient(object): def credentials_headers(self): creds = {} - # NOTE(dhu): (shardy) When deferred_auth_method=password, Heat - # encrypts and stores username/password. For Keystone v3, the - # intent is to use trusts since SHARDY is working towards - # deferred_auth_method=trusts as the default. - # TODO(dhu): Make Keystone v3 work in Heat standalone mode. Maye - # require X-Auth-User-Domain. if self.username: creds['X-Auth-User'] = self.username if self.password: @@ -275,56 +269,3 @@ class HTTPClient(object): def patch(self, url, **kwargs): return self.client_request("PATCH", url, **kwargs) - - -class SessionClient(HTTPClient): - """HTTP client based on Keystone client session.""" - - # NOTE(dhu): Will eventually move to a common session client. - # https://bugs.launchpad.net/python-keystoneclient/+bug/1332337 - def __init__(self, session, auth, **kwargs): - self.session = session - self.auth = auth - - self.auth_url = kwargs.get('auth_url') - self.region_name = kwargs.get('region_name') - self.interface = kwargs.get('interface', - kwargs.get('endpoint_type', 'public')) - self.service_type = kwargs.get('service_type') - - self.include_pass = kwargs.get('include_pass') - self.username = kwargs.get('username') - self.password = kwargs.get('password') - # see if we can get the auth_url from auth plugin if one is not - # provided from kwargs - if not self.auth_url and hasattr(self.auth, 'auth_url'): - self.auth_url = self.auth.auth_url - - def _http_request(self, url, method, **kwargs): - kwargs.setdefault('user_agent', USER_AGENT) - kwargs.setdefault('auth', self.auth) - - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - endpoint_filter.setdefault('interface', self.interface) - endpoint_filter.setdefault('service_type', self.service_type) - endpoint_filter.setdefault('region_name', self.region_name) - - # TODO(gyee): what are these headers for? - if self.auth_url: - kwargs['headers'].setdefault('X-Auth-Url', self.auth_url) - if self.region_name: - kwargs['headers'].setdefault('X-Region-Name', self.region_name) - if self.include_pass and 'X-Auth-Key' not in kwargs['headers']: - kwargs['headers'].update(self.credentials_headers()) - - return self.session.request(url, method, raise_exc=False, **kwargs) - - -def _construct_http_client(*args, **kwargs): - session = kwargs.pop('session', None) - auth = kwargs.pop('auth', None) - - if session: - return SessionClient(session, auth, **kwargs) - else: - return HTTPClient(*args, **kwargs) diff --git a/heatclient/shell.py b/heatclient/shell.py index bf8fb377..cd00ac64 100644 --- a/heatclient/shell.py +++ b/heatclient/shell.py @@ -18,23 +18,15 @@ from __future__ import print_function import argparse import logging +import six import sys -import six -import six.moves.urllib.parse as urlparse - -from keystoneclient.auth.identity import v2 as v2_auth -from keystoneclient.auth.identity import v3 as v3_auth -from keystoneclient.auth import token_endpoint -from keystoneclient import discover -from keystoneclient.openstack.common.apiclient import exceptions as ks_exc -from keystoneclient import session as kssession +from keystoneclient.v2_0 import client as ksclient import heatclient from heatclient import client as heat_client from heatclient.common import utils from heatclient import exc -from heatclient.openstack.common.gettextutils import _ from heatclient.openstack.common import strutils logger = logging.getLogger(__name__) @@ -42,173 +34,6 @@ logger = logging.getLogger(__name__) class HeatShell(object): - def _append_global_identity_args(self, parser): - # FIXME(gyee): these are global identity (Keystone) arguments which - # should be consistent and shared by all service clients. Therefore, - # they should be provided by python-keystoneclient. We will need to - # refactor this code once this functionality is avaible in - # python-keystoneclient. - parser.add_argument('-k', '--insecure', - default=False, - action='store_true', - help='Explicitly allow heatclient to perform ' - '\"insecure SSL\" (https) requests. The server\'s ' - 'certificate will not be verified against any ' - 'certificate authorities. This option should ' - 'be used with caution.') - - parser.add_argument('--os-cert', - help='Path of certificate file to use in SSL ' - 'connection. This file can optionally be ' - 'prepended with the private key.') - - # for backward compatibility only - parser.add_argument('--cert-file', - dest='os_cert', - help='DEPRECATED! Use --os-cert.') - - parser.add_argument('--os-key', - help='Path of client key to use in SSL ' - 'connection. This option is not necessary ' - 'if your key is prepended to your cert file.') - - parser.add_argument('--key-file', - dest='os_key', - help='DEPRECATED! Use --os-key.') - - parser.add_argument('--os-cacert', - metavar='', - dest='os_cacert', - default=utils.env('OS_CACERT'), - help='Path of CA TLS certificate(s) used to ' - 'verify the remote server\'s certificate. ' - 'Without this option glance looks for the ' - 'default system CA certificates.') - - parser.add_argument('--ca-file', - dest='os_cacert', - help='DEPRECATED! Use --os-cacert.') - - parser.add_argument('--os-username', - default=utils.env('OS_USERNAME'), - help='Defaults to env[OS_USERNAME].') - - parser.add_argument('--os_username', - help=argparse.SUPPRESS) - - parser.add_argument('--os-user-id', - default=utils.env('OS_USER_ID'), - help='Defaults to env[OS_USER_ID].') - - parser.add_argument('--os_user_id', - help=argparse.SUPPRESS) - - parser.add_argument('--os-user-domain-id', - default=utils.env('OS_USER_DOMAIN_ID'), - help='Defaults to env[OS_USER_DOMAIN_ID].') - - parser.add_argument('--os_user_domain_id', - help=argparse.SUPPRESS) - - parser.add_argument('--os-user-domain-name', - default=utils.env('OS_USER_DOMAIN_NAME'), - help='Defaults to env[OS_USER_DOMAIN_NAME].') - - parser.add_argument('--os_user_domain_name', - help=argparse.SUPPRESS) - - parser.add_argument('--os-project-id', - default=utils.env('OS_PROJECT_ID'), - help='Another way to specify tenant ID. ' - 'This option is mutually exclusive with ' - ' --os-tenant-id. ' - 'Defaults to env[OS_PROJECT_ID].') - - parser.add_argument('--os_project_id', - help=argparse.SUPPRESS) - - parser.add_argument('--os-project-name', - default=utils.env('OS_PROJECT_NAME'), - help='Another way to specify tenant name. ' - 'This option is mutually exclusive with ' - ' --os-tenant-name. ' - 'Defaults to env[OS_PROJECT_NAME].') - - parser.add_argument('--os_project_name', - help=argparse.SUPPRESS) - - parser.add_argument('--os-project-domain-id', - default=utils.env('OS_PROJECT_DOMAIN_ID'), - help='Defaults to env[OS_PROJECT_DOMAIN_ID].') - - parser.add_argument('--os_project_domain_id', - help=argparse.SUPPRESS) - - parser.add_argument('--os-project-domain-name', - default=utils.env('OS_PROJECT_DOMAIN_NAME'), - help='Defaults to env[OS_PROJECT_DOMAIN_NAME].') - - parser.add_argument('--os_project_domain_name', - help=argparse.SUPPRESS) - - parser.add_argument('--os-password', - default=utils.env('OS_PASSWORD'), - help='Defaults to env[OS_PASSWORD].') - - parser.add_argument('--os_password', - help=argparse.SUPPRESS) - - parser.add_argument('--os-tenant-id', - default=utils.env('OS_TENANT_ID'), - help='Defaults to env[OS_TENANT_ID].') - - parser.add_argument('--os_tenant_id', - default=utils.env('OS_TENANT_ID'), - help=argparse.SUPPRESS) - - parser.add_argument('--os-tenant-name', - default=utils.env('OS_TENANT_NAME'), - help='Defaults to env[OS_TENANT_NAME].') - - parser.add_argument('--os_tenant_name', - default=utils.env('OS_TENANT_NAME'), - help=argparse.SUPPRESS) - - parser.add_argument('--os-auth-url', - default=utils.env('OS_AUTH_URL'), - help='Defaults to env[OS_AUTH_URL].') - - parser.add_argument('--os_auth_url', - help=argparse.SUPPRESS) - - parser.add_argument('--os-region-name', - default=utils.env('OS_REGION_NAME'), - help='Defaults to env[OS_REGION_NAME].') - - parser.add_argument('--os_region_name', - help=argparse.SUPPRESS) - - parser.add_argument('--os-auth-token', - default=utils.env('OS_AUTH_TOKEN'), - help='Defaults to env[OS_AUTH_TOKEN].') - - parser.add_argument('--os_auth_token', - help=argparse.SUPPRESS) - - parser.add_argument('--os-service-type', - default=utils.env('OS_SERVICE_TYPE'), - help='Defaults to env[OS_SERVICE_TYPE].') - - parser.add_argument('--os_service_type', - help=argparse.SUPPRESS) - - parser.add_argument('--os-endpoint-type', - default=utils.env('OS_ENDPOINT_TYPE'), - help='Defaults to env[OS_ENDPOINT_TYPE].') - - parser.add_argument('--os_endpoint_type', - help=argparse.SUPPRESS) - def get_base_parser(self): parser = argparse.ArgumentParser( prog='heat', @@ -238,13 +63,92 @@ class HeatShell(object): default=False, action="store_true", help="Print more verbose output.") + parser.add_argument('-k', '--insecure', + default=False, + action='store_true', + help="Explicitly allow the client to perform " + "\"insecure\" SSL (https) requests. The server's " + "certificate will not be verified against any " + "certificate authorities. " + "This option should be used with caution.") + + parser.add_argument('--os-cacert', + metavar='', + default=utils.env('OS_CACERT', default=None), + help='Specify a CA bundle file to use in ' + 'verifying a TLS (https) server certificate. ' + 'Defaults to env[OS_CACERT]') + + parser.add_argument('--cert-file', + help='Path of certificate file to use in SSL ' + 'connection. This file can optionally be ' + 'prepended with the private key.') + + parser.add_argument('--key-file', + help='Path of client key to use in SSL connection.' + 'This option is not necessary if your key is' + ' prepended to your cert file.') + + parser.add_argument('--ca-file', + help='Path of CA SSL certificate(s) used to verify' + ' the remote server\'s certificate. Without this' + ' option the client looks' + ' for the default system CA certificates.') + parser.add_argument('--api-timeout', help='Number of seconds to wait for an ' 'API response, ' 'defaults to system socket timeout') - # os-no-client-auth tells heatclient to use token, instead of - # env[OS_AUTH_URL] + parser.add_argument('--os-username', + default=utils.env('OS_USERNAME'), + help='Defaults to env[OS_USERNAME].') + + parser.add_argument('--os_username', + help=argparse.SUPPRESS) + + parser.add_argument('--os-password', + default=utils.env('OS_PASSWORD'), + help='Defaults to env[OS_PASSWORD].') + + parser.add_argument('--os_password', + help=argparse.SUPPRESS) + + parser.add_argument('--os-tenant-id', + default=utils.env('OS_TENANT_ID'), + help='Defaults to env[OS_TENANT_ID].') + + parser.add_argument('--os_tenant_id', + help=argparse.SUPPRESS) + + parser.add_argument('--os-tenant-name', + default=utils.env('OS_TENANT_NAME'), + help='Defaults to env[OS_TENANT_NAME].') + + parser.add_argument('--os_tenant_name', + help=argparse.SUPPRESS) + + parser.add_argument('--os-auth-url', + default=utils.env('OS_AUTH_URL'), + help='Defaults to env[OS_AUTH_URL].') + + parser.add_argument('--os_auth_url', + help=argparse.SUPPRESS) + + parser.add_argument('--os-region-name', + default=utils.env('OS_REGION_NAME'), + help='Defaults to env[OS_REGION_NAME].') + + parser.add_argument('--os_region_name', + help=argparse.SUPPRESS) + + parser.add_argument('--os-auth-token', + default=utils.env('OS_AUTH_TOKEN'), + help='Defaults to env[OS_AUTH_TOKEN].') + + parser.add_argument('--os_auth_token', + help=argparse.SUPPRESS) + parser.add_argument('--os-no-client-auth', default=utils.env('OS_NO_CLIENT_AUTH'), action='store_true', @@ -265,6 +169,20 @@ class HeatShell(object): parser.add_argument('--heat_api_version', help=argparse.SUPPRESS) + parser.add_argument('--os-service-type', + default=utils.env('OS_SERVICE_TYPE'), + help='Defaults to env[OS_SERVICE_TYPE].') + + parser.add_argument('--os_service_type', + help=argparse.SUPPRESS) + + parser.add_argument('--os-endpoint-type', + default=utils.env('OS_ENDPOINT_TYPE'), + help='Defaults to env[OS_ENDPOINT_TYPE].') + + parser.add_argument('--os_endpoint_type', + help=argparse.SUPPRESS) + # This unused option should remain so that scripts that # use it do not break. It is suppressed so it will not # appear in the help. @@ -278,12 +196,6 @@ class HeatShell(object): action='store_true', help='Send os-username and os-password to heat.') - # FIXME(gyee): this method should come from python-keystoneclient. - # Will refactor this code once it is available. - # https://bugs.launchpad.net/python-keystoneclient/+bug/1332337 - - self._append_global_identity_args(parser) - return parser def get_subcommand_parser(self, version): @@ -329,6 +241,45 @@ class HeatShell(object): subparser.add_argument(*args, **kwargs) subparser.set_defaults(func=callback) + def _get_ksclient(self, **kwargs): + """Get an endpoint and auth token from Keystone. + + :param username: name of user + :param password: user's password + :param tenant_id: unique identifier of tenant + :param tenant_name: name of tenant + :param auth_url: endpoint to authenticate against + :param token: token to use instead of username/password + """ + kc_args = {'auth_url': kwargs.get('auth_url'), + 'insecure': kwargs.get('insecure'), + 'cacert': kwargs.get('cacert')} + + if kwargs.get('tenant_id'): + kc_args['tenant_id'] = kwargs.get('tenant_id') + else: + kc_args['tenant_name'] = kwargs.get('tenant_name') + + if kwargs.get('token'): + kc_args['token'] = kwargs.get('token') + else: + kc_args['username'] = kwargs.get('username') + kc_args['password'] = kwargs.get('password') + + return ksclient.Client(**kc_args) + + def _get_endpoint(self, client, **kwargs): + """Get an endpoint using the provided keystone client.""" + if kwargs.get('region_name'): + return client.service_catalog.url_for( + service_type=kwargs.get('service_type') or 'orchestration', + attr='region', + filter_value=kwargs.get('region_name'), + endpoint_type=kwargs.get('endpoint_type') or 'publicURL') + return client.service_catalog.url_for( + service_type=kwargs.get('service_type') or 'orchestration', + endpoint_type=kwargs.get('endpoint_type') or 'publicURL') + def _setup_logging(self, debug): log_lvl = logging.DEBUG if debug else logging.WARNING logging.basicConfig( @@ -341,132 +292,6 @@ class HeatShell(object): if verbose: exc.verbose = 1 - def _discover_auth_versions(self, session, auth_url): - # discover the API versions the server is supporting base on the - # given URL - v2_auth_url = None - v3_auth_url = None - try: - ks_discover = discover.Discover(session=session, auth_url=auth_url) - v2_auth_url = ks_discover.url_for('2.0') - v3_auth_url = ks_discover.url_for('3.0') - except ks_exc.ClientException: - # Identity service may not support discover API version. - # Lets trying to figure out the API version from the original URL. - url_parts = urlparse.urlparse(auth_url) - (scheme, netloc, path, params, query, fragment) = url_parts - path = path.lower() - if path.startswith('/v3'): - v3_auth_url = auth_url - elif path.startswith('/v2'): - v2_auth_url = auth_url - else: - # not enough information to determine the auth version - msg = _('Unable to determine the Keystone version ' - 'to authenticate with using the given ' - 'auth_url. Identity service may not support API ' - 'version discovery. Please provide a versioned ' - 'auth_url instead.') - raise exc.CommandError(msg) - - return (v2_auth_url, v3_auth_url) - - def _get_keystone_session(self, **kwargs): - # first create a Keystone session - cacert = kwargs.pop('cacert', None) - cert = kwargs.pop('cert', None) - key = kwargs.pop('key', None) - insecure = kwargs.pop('insecure', False) - timeout = kwargs.pop('timeout', None) - verify = kwargs.pop('verify', None) - - # FIXME(gyee): this code should come from keystoneclient - if verify is None: - if insecure: - verify = False - else: - # TODO(gyee): should we do - # heatclient.common.http.get_system_ca_fle()? - verify = cacert or True - if cert and key: - # passing cert and key together is deprecated in favour of the - # requests lib form of having the cert and key as a tuple - cert = (cert, key) - - return kssession.Session(verify=verify, cert=cert, timeout=timeout) - - def _get_keystone_auth(self, session, auth_url, **kwargs): - # FIXME(gyee): this code should come from keystoneclient - # https://bugs.launchpad.net/python-keystoneclient/+bug/1332337 - - auth_token = kwargs.pop('auth_token', None) - # static token auth only - if auth_token: - endpoint = kwargs.pop('endpoint', None) - return token_endpoint.Token(endpoint, auth_token) - - # discover the supported keystone versions using the given url - (v2_auth_url, v3_auth_url) = self._discover_auth_versions( - session=session, - auth_url=auth_url) - - # Determine which authentication plugin to use. First inspect the - # auth_url to see the supported version. If both v3 and v2 are - # supported, then use the highest version if possible. - username = kwargs.pop('username', None) - user_id = kwargs.pop('user_id', None) - user_domain_name = kwargs.pop('user_domain_name', None) - user_domain_id = kwargs.pop('user_domain_id', None) - project_domain_name = kwargs.pop('project_domain_name', None) - project_domain_id = kwargs.pop('project_domain_id', None) - auth = None - if v3_auth_url and v2_auth_url: - # support both v2 and v3 auth. Use v3 if domain information is - # provided. - if (user_domain_name or user_domain_id or project_domain_name or - project_domain_id): - auth = v3_auth.Password( - v3_auth_url, - username=username, - user_id=user_id, - user_domain_name=user_domain_name, - user_domain_id=user_domain_id, - project_domain_name=project_domain_name, - project_domain_id=project_domain_id, - **kwargs) - else: - auth = v2_auth.Password( - v2_auth_url, - username, - kwargs.pop('password', None), - tenant_id=kwargs.pop('project_id', None), - tenant_name=kwargs.pop('project_name', None)) - elif v3_auth_url: - # support only v3 - auth = v3_auth.Password( - v3_auth_url, - username=username, - user_id=user_id, - user_domain_name=user_domain_name, - user_domain_id=user_domain_id, - project_domain_name=project_domain_name, - project_domain_id=project_domain_id, - **kwargs) - elif v2_auth_url: - # support only v2 - auth = v2_auth.Password( - v2_auth_url, - username, - kwargs.pop('password', None), - tenant_id=kwargs.pop('project_id', None), - tenant_name=kwargs.pop('project_name', None)) - else: - raise exc.CommandError('Unable to determine the Keystone version ' - 'to authenticate with using the given ' - 'auth_url.') - - return auth - def main(self, argv): # Parse args once to find version parser = self.get_base_parser() @@ -515,21 +340,13 @@ class HeatShell(object): " via either --heat-url or" " env[HEAT_URL]") else: - # Tenant/project name or ID is needed to make keystoneclient - # retrieve a service catalog, it's not required if - # os_no_client_auth is specified, neither is the auth URL - - if not (args.os_tenant_id or args.os_tenant_name or - args.os_project_id or args.os_project_name): - raise exc.CommandError("You must provide a tenant id via" - " either --os-tenant-id or" - " env[OS_TENANT_ID] or a tenant name" - " via either --os-tenant-name or" - " env[OS_TENANT_NAME] or a project id" - " via either --os-project-id or" - " env[OS_PROJECT_ID] or a project" - " name via either --os-project-name or" - " env[OS_PROJECT_NAME]") + # Tenant name or ID is needed to make keystoneclient retrieve a + # service catalog, it's not required if os_no_client_auth is + # specified, neither is the auth URL + if not (args.os_tenant_id or args.os_tenant_name): + raise exc.CommandError("You must provide a tenant_id via" + " either --os-tenant-id or via" + " env[OS_TENANT_ID]") if not args.os_auth_url: raise exc.CommandError("You must provide an auth url via" @@ -537,55 +354,46 @@ class HeatShell(object): " env[OS_AUTH_URL]") kwargs = { - 'insecure': args.insecure, - 'cacert': args.os_cacert, - 'cert': args.os_cert, - 'key': args.os_key, - 'timeout': args.api_timeout - } - keystone_session = self._get_keystone_session(**kwargs) - - endpoint = args.heat_url - if args.os_no_client_auth: - kwargs = { - 'endpoint': endpoint, - 'auth_token': args.os_auth_token} - keystone_auth = self._get_keystone_auth(keystone_session, - args.os_auth_url, - **kwargs) - else: - project_id = args.os_project_id or args.os_tenant_id - project_name = args.os_project_name or args.os_tenant_name - kwargs = { - 'username': args.os_username, - 'user_id': args.os_user_id, - 'user_domain_id': args.os_user_domain_id, - 'user_domain_name': args.os_user_domain_name, - 'password': args.os_password, - 'auth_token': args.os_auth_token, - 'project_id': project_id, - 'project_name': project_name, - 'project_domain_id': args.os_project_domain_id, - 'project_domain_name': args.os_project_domain_name, - } - keystone_auth = self._get_keystone_auth(keystone_session, - args.os_auth_url, - **kwargs) - - service_type = args.os_service_type or 'orchestration' - endpoint_type = args.os_endpoint_type or 'publicURL' - kwargs = { - 'auth_url': args.os_auth_url, - 'session': keystone_session, - 'auth': keystone_auth, - 'service_type': service_type, - 'endpoint_type': endpoint_type, - 'region_name': args.os_region_name, 'username': args.os_username, 'password': args.os_password, + 'token': args.os_auth_token, + 'tenant_id': args.os_tenant_id, + 'tenant_name': args.os_tenant_name, + 'auth_url': args.os_auth_url, + 'service_type': args.os_service_type, + 'endpoint_type': args.os_endpoint_type, + 'insecure': args.insecure, + 'cacert': args.os_cacert, 'include_pass': args.include_password } + endpoint = args.heat_url + + if not args.os_no_client_auth: + _ksclient = self._get_ksclient(**kwargs) + token = args.os_auth_token or _ksclient.auth_token + + kwargs = { + 'token': token, + 'insecure': args.insecure, + 'ca_file': args.ca_file, + 'cert_file': args.cert_file, + 'key_file': args.key_file, + 'username': args.os_username, + 'password': args.os_password, + 'endpoint_type': args.os_endpoint_type, + 'include_pass': args.include_password + } + + if args.os_region_name: + kwargs['region_name'] = args.os_region_name + + if not endpoint: + endpoint = self._get_endpoint(_ksclient, **kwargs) + + if args.api_timeout: + kwargs['timeout'] = args.api_timeout + client = heat_client.Client(api_version, endpoint, **kwargs) args.func(client, args) diff --git a/heatclient/tests/fakes.py b/heatclient/tests/fakes.py index 8ce25ea2..f0c6ba00 100644 --- a/heatclient/tests/fakes.py +++ b/heatclient/tests/fakes.py @@ -14,6 +14,24 @@ from heatclient.common import http from heatclient import exc from heatclient.openstack.common import jsonutils +from keystoneclient.v2_0 import client as ksclient + + +def script_keystone_client(token=None): + if token: + ksclient.Client(auth_url='http://no.where', + insecure=False, + cacert=None, + tenant_id='tenant_id', + token=token).AndReturn(FakeKeystone(token)) + else: + ksclient.Client(auth_url='http://no.where', + insecure=False, + cacert=None, + password='password', + tenant_name='tenant_name', + username='username').AndReturn(FakeKeystone( + 'abcd1234')) def script_heat_list(url=None): diff --git a/heatclient/tests/keystone_client_fixtures.py b/heatclient/tests/keystone_client_fixtures.py deleted file mode 100644 index cd2104d5..00000000 --- a/heatclient/tests/keystone_client_fixtures.py +++ /dev/null @@ -1,83 +0,0 @@ -# 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 heatclient.openstack.common import jsonutils -from keystoneclient.fixture import v2 as ks_v2_fixture -from keystoneclient.fixture import v3 as ks_v3_fixture - -# these are copied from python-keystoneclient tests -BASE_HOST = 'http://keystone.example.com' -BASE_URL = "%s:5000/" % BASE_HOST -UPDATED = '2013-03-06T00:00:00Z' - -V2_URL = "%sv2.0" % BASE_URL -V2_DESCRIBED_BY_HTML = {'href': 'http://docs.openstack.org/api/' - 'openstack-identity-service/2.0/content/', - 'rel': 'describedby', - 'type': 'text/html'} -V2_DESCRIBED_BY_PDF = {'href': 'http://docs.openstack.org/api/openstack-ident' - 'ity-service/2.0/identity-dev-guide-2.0.pdf', - 'rel': 'describedby', - 'type': 'application/pdf'} - -V2_VERSION = {'id': 'v2.0', - 'links': [{'href': V2_URL, 'rel': 'self'}, - V2_DESCRIBED_BY_HTML, V2_DESCRIBED_BY_PDF], - 'status': 'stable', - 'updated': UPDATED} - -V3_URL = "%sv3" % BASE_URL -V3_MEDIA_TYPES = [{'base': 'application/json', - 'type': 'application/vnd.openstack.identity-v3+json'}, - {'base': 'application/xml', - 'type': 'application/vnd.openstack.identity-v3+xml'}] - -V3_VERSION = {'id': 'v3.0', - 'links': [{'href': V3_URL, 'rel': 'self'}], - 'media-types': V3_MEDIA_TYPES, - 'status': 'stable', - 'updated': UPDATED} - -TOKENID = uuid.uuid4().hex - - -def _create_version_list(versions): - return jsonutils.dumps({'versions': {'values': versions}}) - - -def _create_single_version(version): - return jsonutils.dumps({'version': version}) - - -V3_VERSION_LIST = _create_version_list([V3_VERSION, V2_VERSION]) -V2_VERSION_LIST = _create_version_list([V2_VERSION]) - -V3_VERSION_ENTRY = _create_single_version(V3_VERSION) -V2_VERSION_ENTRY = _create_single_version(V2_VERSION) - -HEAT_ENDPOINT = 'http://www.heat.com/v1' - - -def keystone_request_callback(request, uri, headers): - response_headers = {"content-type": "application/json"} - token_id = TOKENID - if uri == BASE_URL: - return (200, headers, V3_VERSION_LIST) - elif uri == BASE_URL + "/v2.0": - v2_token = ks_v2_fixture.Token(token_id) - return (200, response_headers, jsonutils.dumps(v2_token)) - elif uri == BASE_URL + "/v3": - v3_token = ks_v3_fixture.Token() - response_headers["X-Subject-Token"] = token_id - return (201, response_headers, jsonutils.dumps(v3_token)) diff --git a/heatclient/tests/test_shell.py b/heatclient/tests/test_shell.py index 19519e2a..91d4507d 100644 --- a/heatclient/tests/test_shell.py +++ b/heatclient/tests/test_shell.py @@ -19,7 +19,6 @@ from six.moves.urllib import request import sys import fixtures -import httpretty import tempfile import testscenarios import testtools @@ -28,32 +27,18 @@ from heatclient.openstack.common import jsonutils from heatclient.openstack.common import strutils from mox3 import mox +from keystoneclient.v2_0 import client as ksclient + from heatclient.common import http from heatclient import exc import heatclient.shell from heatclient.tests import fakes -from heatclient.tests import keystone_client_fixtures + load_tests = testscenarios.load_tests_apply_scenarios TEST_VAR_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'var')) -FAKE_ENV_KEYSTONE_V2 = { - 'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': keystone_client_fixtures.BASE_URL, -} - -FAKE_ENV_KEYSTONE_V3 = { - 'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': keystone_client_fixtures.BASE_URL, - 'OS_USER_DOMAIN_ID': 'default', - 'OS_PROJECT_DOMAIN_ID': 'default', -} - class TestCase(testtools.TestCase): @@ -89,12 +74,6 @@ class TestCase(testtools.TestCase): sys.stderr = orig return err - def register_keystone_auth_fixture(self): - httpretty.register_uri( - httpretty.GET, - keystone_client_fixtures.BASE_URL, - body=keystone_client_fixtures.keystone_request_callback) - class EnvVarTest(TestCase): @@ -107,7 +86,7 @@ class EnvVarTest(TestCase): err='You must provide a password')), ('tenant_name', dict( remove='OS_TENANT_NAME', - err='You must provide a tenant id')), + err='You must provide a tenant_id')), ('auth_url', dict( remove='OS_AUTH_URL', err='You must provide an auth url')), @@ -131,7 +110,7 @@ class EnvVarTestToken(TestCase): scenarios = [ ('tenant_id', dict( remove='OS_TENANT_ID', - err='You must provide a tenant id')), + err='You must provide a tenant_id')), ('auth_url', dict( remove='OS_AUTH_URL', err='You must provide an auth url')), @@ -172,14 +151,17 @@ class ShellParamValidationTest(TestCase): self.addCleanup(self.m.VerifyAll) self.addCleanup(self.m.UnsetStubs) - @httpretty.activate def test_bad_parameters(self): - self.register_keystone_auth_fixture() + self.m.StubOutWithMock(ksclient, 'Client') + self.m.StubOutWithMock(http.HTTPClient, 'json_request') + fakes.script_keystone_client() + + self.m.ReplayAll() fake_env = { 'OS_USERNAME': 'username', 'OS_PASSWORD': 'password', 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': keystone_client_fixtures.BASE_URL, + 'OS_AUTH_URL': 'http://no.where', } self.set_fake_env(fake_env) template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') @@ -195,63 +177,35 @@ class ShellValidationTest(TestCase): self.addCleanup(self.m.VerifyAll) self.addCleanup(self.m.UnsetStubs) - @httpretty.activate def test_failed_auth(self): - self.register_keystone_auth_fixture() + self.m.StubOutWithMock(ksclient, 'Client') self.m.StubOutWithMock(http.HTTPClient, 'json_request') + fakes.script_keystone_client() failed_msg = 'Unable to authenticate user with credentials provided' http.HTTPClient.json_request( 'GET', '/stacks?').AndRaise(exc.Unauthorized(failed_msg)) self.m.ReplayAll() - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) - self.shell_error('stack-list', failed_msg) - - @httpretty.activate - def test_stack_create_validation(self): - # emulate Keystone version discovery - httpretty.register_uri( - httpretty.GET, - keystone_client_fixtures.V2_URL, - body=keystone_client_fixtures.V2_VERSION_ENTRY) - # emulate Keystone v2 token request - httpretty.register_uri( - httpretty.POST, - '%s/tokens' % (keystone_client_fixtures.V2_URL), - body=keystone_client_fixtures.keystone_request_callback) - fake_env = { 'OS_USERNAME': 'username', 'OS_PASSWORD': 'password', 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': keystone_client_fixtures.V2_URL, + 'OS_AUTH_URL': 'http://no.where', } self.set_fake_env(fake_env) - self.shell_error( - 'stack-create teststack ' - '--parameters="InstanceType=m1.large;DBUsername=wp;' - 'DBPassword=verybadpassword;KeyName=heat_key;' - 'LinuxDistribution=F17"', - 'Need to specify exactly one of') + self.shell_error('stack-list', failed_msg) - @httpretty.activate - def test_stack_create_validation_keystone_v3(self): - # emulate Keystone version discovery - httpretty.register_uri( - httpretty.GET, - keystone_client_fixtures.V3_URL, - body=keystone_client_fixtures.V3_VERSION_ENTRY) - # emulate Keystone v2 token request - httpretty.register_uri( - httpretty.POST, - '%s/tokens' % (keystone_client_fixtures.V3_URL), - body=keystone_client_fixtures.keystone_request_callback) + def test_stack_create_validation(self): + self.m.StubOutWithMock(ksclient, 'Client') + self.m.StubOutWithMock(http.HTTPClient, 'json_request') + fakes.script_keystone_client() + self.m.ReplayAll() fake_env = { 'OS_USERNAME': 'username', 'OS_PASSWORD': 'password', 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': keystone_client_fixtures.V3_URL, + 'OS_AUTH_URL': 'http://no.where', } self.set_fake_env(fake_env) self.shell_error( @@ -267,6 +221,7 @@ class ShellBase(TestCase): def setUp(self): super(ShellBase, self).setUp() self.m = mox.Mox() + self.m.StubOutWithMock(ksclient, 'Client') self.m.StubOutWithMock(http.HTTPClient, 'json_request') self.m.StubOutWithMock(http.HTTPClient, 'raw_request') self.addCleanup(self.m.VerifyAll) @@ -300,7 +255,6 @@ class ShellTestCommon(ShellBase): def setUp(self): super(ShellTestCommon, self).setUp() - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) def test_help_unknown_command(self): self.assertRaises(exc.CommandError, self.shell, 'help foofoo') @@ -327,36 +281,54 @@ class ShellTestCommon(ShellBase): self.assertEqual(output1, output2) self.assertRegexpMatches(output1, '^usage: heat %s' % command) - @httpretty.activate def test_debug_switch_raises_error(self): - self.register_keystone_auth_fixture() + fakes.script_keystone_client() http.HTTPClient.json_request( 'GET', '/stacks?').AndRaise(exc.Unauthorized("FAIL")) self.m.ReplayAll() + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) args = ['--debug', 'stack-list'] self.assertRaises(exc.Unauthorized, heatclient.shell.main, args) - @httpretty.activate def test_dash_d_switch_raises_error(self): - self.register_keystone_auth_fixture() + fakes.script_keystone_client() http.HTTPClient.json_request( 'GET', '/stacks?').AndRaise(exc.CommandError("FAIL")) self.m.ReplayAll() + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) args = ['-d', 'stack-list'] self.assertRaises(exc.CommandError, heatclient.shell.main, args) - @httpretty.activate def test_no_debug_switch_no_raises_errors(self): - self.register_keystone_auth_fixture() + fakes.script_keystone_client() http.HTTPClient.json_request( 'GET', '/stacks?').AndRaise(exc.Unauthorized("FAIL")) self.m.ReplayAll() + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) args = ['stack-list'] self.assertRaises(SystemExit, heatclient.shell.main, args) @@ -380,12 +352,21 @@ class ShellTestUserPass(ShellBase): super(ShellTestUserPass, self).setUp() self._set_fake_env() + # Patch os.environ to avoid required auth info. def _set_fake_env(self): - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + + def _script_keystone_client(self): + fakes.script_keystone_client() - @httpretty.activate def test_stack_list(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() fakes.script_heat_list() self.m.ReplayAll() @@ -404,9 +385,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(list_text, r) - @httpretty.activate def test_stack_list_with_args(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() expected_url = '/stacks?%s' % parse.urlencode({ 'limit': 2, 'status': ['COMPLETE', 'FAILED'], @@ -433,9 +413,7 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(list_text, r) - @httpretty.activate def test_parsable_error(self): - self.register_keystone_auth_fixture() message = "The Stack (bad) could not be found." resp_dict = { "explanation": "The resource could not be found.", @@ -448,6 +426,7 @@ class ShellTestUserPass(ShellBase): "title": "Not Found" } + self._script_keystone_client() fakes.script_heat_error(jsonutils.dumps(resp_dict)) self.m.ReplayAll() @@ -455,9 +434,7 @@ class ShellTestUserPass(ShellBase): e = self.assertRaises(exc.HTTPException, self.shell, "stack-show bad") self.assertEqual("ERROR: " + message, str(e)) - @httpretty.activate def test_parsable_verbose(self): - self.register_keystone_auth_fixture() message = "The Stack (bad) could not be found." resp_dict = { "explanation": "The resource could not be found.", @@ -470,6 +447,7 @@ class ShellTestUserPass(ShellBase): "title": "Not Found" } + self._script_keystone_client() fakes.script_heat_error(jsonutils.dumps(resp_dict)) self.m.ReplayAll() @@ -479,18 +457,15 @@ class ShellTestUserPass(ShellBase): e = self.assertRaises(exc.HTTPException, self.shell, "stack-show bad") self.assertIn(message, str(e)) - @httpretty.activate def test_parsable_malformed_error(self): - self.register_keystone_auth_fixture() invalid_json = "ERROR: {Invalid JSON Error." + self._script_keystone_client() fakes.script_heat_error(invalid_json) self.m.ReplayAll() e = self.assertRaises(exc.HTTPException, self.shell, "stack-show bad") self.assertEqual("ERROR: " + invalid_json, str(e)) - @httpretty.activate def test_parsable_malformed_error_missing_message(self): - self.register_keystone_auth_fixture() missing_message = { "explanation": "The resource could not be found.", "code": 404, @@ -501,15 +476,14 @@ class ShellTestUserPass(ShellBase): "title": "Not Found" } + self._script_keystone_client() fakes.script_heat_error(jsonutils.dumps(missing_message)) self.m.ReplayAll() e = self.assertRaises(exc.HTTPException, self.shell, "stack-show bad") self.assertEqual("ERROR: Internal Error", str(e)) - @httpretty.activate def test_parsable_malformed_error_missing_traceback(self): - self.register_keystone_auth_fixture() message = "The Stack (bad) could not be found." resp_dict = { "explanation": "The resource could not be found.", @@ -521,6 +495,7 @@ class ShellTestUserPass(ShellBase): "title": "Not Found" } + self._script_keystone_client() fakes.script_heat_error(jsonutils.dumps(resp_dict)) self.m.ReplayAll() @@ -530,9 +505,8 @@ class ShellTestUserPass(ShellBase): self.assertEqual("ERROR: The Stack (bad) could not be found.\n", str(e)) - @httpretty.activate def test_stack_show(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"stack": { "id": "1", "stack_name": "teststack", @@ -563,9 +537,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(list_text, r) - @httpretty.activate def test_stack_abandon(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"stack": { "id": "1", @@ -607,6 +580,7 @@ class ShellTestUserPass(ShellBase): self.assertEqual(abandoned_stack, jsonutils.loads(abandon_resp)) def _output_fake_response(self): + self._script_keystone_client() resp_dict = {"stack": { "id": "1", @@ -644,31 +618,24 @@ class ShellTestUserPass(ShellBase): self.m.ReplayAll() - @httpretty.activate def test_output_list(self): - self.register_keystone_auth_fixture() self._output_fake_response() list_text = self.shell('output-list teststack/1') for r in ['output1', 'output2', 'output_uni']: self.assertRegexpMatches(list_text, r) - @httpretty.activate def test_output_show(self): - self.register_keystone_auth_fixture() self._output_fake_response() list_text = self.shell('output-show teststack/1 output1') self.assertRegexpMatches(list_text, 'value1') - @httpretty.activate def test_output_show_unicode(self): - self.register_keystone_auth_fixture() self._output_fake_response() list_text = self.shell('output-show teststack/1 output_uni') self.assertRegexpMatches(list_text, u'test\u2665') - @httpretty.activate def test_template_show_cfn(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() template_data = open(os.path.join(TEST_VAR_DIR, 'minimal.template')).read() resp = fakes.FakeHTTPResponse( @@ -694,9 +661,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(show_text, r) - @httpretty.activate def test_template_show_cfn_unicode(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"AWSTemplateFormatVersion": "2010-09-09", "Description": u"test\u2665", "Outputs": {}, @@ -725,9 +691,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(show_text, r) - @httpretty.activate def test_template_show_hot(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"heat_template_version": "2013-05-23", "parameters": {}, "resources": {}, @@ -752,9 +717,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(show_text, r) - @httpretty.activate def test_stack_preview(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"stack": { "id": "1", "stack_name": "teststack", @@ -793,9 +757,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(preview_text, r) - @httpretty.activate def test_stack_create(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 201, 'Created', @@ -827,9 +790,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(create_text, r) - @httpretty.activate def test_stack_create_timeout(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') template_data = open(template_file).read() resp = fakes.FakeHTTPResponse( @@ -875,9 +837,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(create_text, r) - @httpretty.activate def test_stack_update_timeout(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') template_data = open(template_file).read() resp = fakes.FakeHTTPResponse( @@ -923,9 +884,9 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(update_text, r) - @httpretty.activate def test_stack_create_url(self): - self.register_keystone_auth_fixture() + + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 201, 'Created', @@ -971,9 +932,9 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(create_text, r) - @httpretty.activate def test_stack_create_object(self): - self.register_keystone_auth_fixture() + + self._script_keystone_client() template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') template_data = open(template_file).read() http.HTTPClient.raw_request( @@ -1011,9 +972,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(create_text, r) - @httpretty.activate def test_stack_adopt(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 201, 'Created', @@ -1047,19 +1007,17 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(adopt_text, r) - @httpretty.activate def test_stack_adopt_without_data(self): - self.register_keystone_auth_fixture() failed_msg = 'Need to specify --adopt-file' + self._script_keystone_client() self.m.ReplayAll() template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') self.shell_error( 'stack-adopt teststack ' '--template-file=%s ' % template_file, failed_msg) - @httpretty.activate def test_stack_update(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 202, 'Accepted', @@ -1092,9 +1050,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(update_text, r) - @httpretty.activate def test_stack_delete(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 204, 'No Content', @@ -1118,9 +1075,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(delete_text, r) - @httpretty.activate def test_stack_delete_multiple(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 204, 'No Content', @@ -1147,9 +1103,8 @@ class ShellTestUserPass(ShellBase): for r in required: self.assertRegexpMatches(delete_text, r) - @httpretty.activate def test_build_info(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = { 'build_info': { 'api': {'revision': 'api_revision'}, @@ -1178,10 +1133,22 @@ class ShellTestUserPass(ShellBase): class ShellTestEvents(ShellBase): - def setUp(self): super(ShellTestEvents, self).setUp() - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) + self._set_fake_env() + + # Patch os.environ to avoid required auth info. + def _set_fake_env(self): + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + + def _script_keystone_client(self): + fakes.script_keystone_client() scenarios = [ ('integer_id', dict( @@ -1191,9 +1158,8 @@ class ShellTestEvents(ShellBase): event_id_one='3d68809e-c4aa-4dc9-a008-933823d2e44f', event_id_two='43b68bae-ed5d-4aed-a99f-0b3d39c2418a'))] - @httpretty.activate def test_event_list(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"events": [ {"event_time": "2013-12-05T14:14:30Z", "id": self.event_id_one, @@ -1258,9 +1224,8 @@ class ShellTestEvents(ShellBase): for r in required: self.assertRegexpMatches(event_list_text, r) - @httpretty.activate def test_event_list_pagination(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() # test for pagination resp_dict = {"events": [ {"event_time": "2013-12-05T14:14:30Z", @@ -1312,9 +1277,8 @@ class ShellTestEvents(ShellBase): for r in required: self.assertRegexpMatches(event_list_text, r) - @httpretty.activate def test_event_show(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"event": {"event_time": "2013-12-05T14:14:30Z", "id": self.event_id_one, @@ -1383,13 +1347,25 @@ class ShellTestEvents(ShellBase): class ShellTestResources(ShellBase): - def setUp(self): super(ShellTestResources, self).setUp() - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) + self._set_fake_env() + + # Patch os.environ to avoid required auth info. + def _set_fake_env(self): + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + + def _script_keystone_client(self): + fakes.script_keystone_client() def _test_resource_list(self, with_resource_name): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"resources": [ {"links": [{"href": "http://heat.example.com:8004/foo", "rel": "self"}, @@ -1438,17 +1414,14 @@ class ShellTestResources(ShellBase): for r in required: self.assertRegexpMatches(resource_list_text, r) - @httpretty.activate def test_resource_list(self): self._test_resource_list(True) - @httpretty.activate def test_resource_list_no_resource_name(self): self._test_resource_list(False) - @httpretty.activate def test_resource_list_empty(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"resources": []} resp = fakes.FakeHTTPResponse( 200, @@ -1475,9 +1448,8 @@ class ShellTestResources(ShellBase): --------------+ ''', resource_list_text) - @httpretty.activate def test_resource_show(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"resource": {"description": "", "links": [{"href": "http://heat.example.com:8004/foo", @@ -1536,9 +1508,8 @@ class ShellTestResources(ShellBase): for r in required: self.assertRegexpMatches(resource_show_text, r) - @httpretty.activate def test_resource_signal(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 200, 'OK', @@ -1562,9 +1533,8 @@ class ShellTestResources(ShellBase): stack_id, resource_name)) self.assertEqual("", text) - @httpretty.activate def test_resource_signal_no_data(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 200, 'OK', @@ -1586,9 +1556,8 @@ class ShellTestResources(ShellBase): 'resource-signal {0} {1}'.format(stack_id, resource_name)) self.assertEqual("", text) - @httpretty.activate def test_resource_signal_no_json(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() stack_id = 'teststack/1' resource_name = 'aResource' @@ -1600,9 +1569,8 @@ class ShellTestResources(ShellBase): stack_id, resource_name)) self.assertIn('Data should be in JSON format', str(error)) - @httpretty.activate def test_resource_signal_no_dict(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() stack_id = 'teststack/1' resource_name = 'aResource' @@ -1614,9 +1582,8 @@ class ShellTestResources(ShellBase): stack_id, resource_name)) self.assertEqual('Data should be a JSON dict', str(error)) - @httpretty.activate def test_resource_signal_both_data(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() stack_id = 'teststack/1' resource_name = 'aResource' @@ -1629,9 +1596,8 @@ class ShellTestResources(ShellBase): self.assertEqual('Can only specify one of data and data-file', str(error)) - @httpretty.activate def test_resource_signal_data_file(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 200, 'OK', @@ -1662,11 +1628,23 @@ class ShellTestResources(ShellBase): class ShellTestResourceTypes(ShellBase): def setUp(self): super(ShellTestResourceTypes, self).setUp() - self.set_fake_env(FAKE_ENV_KEYSTONE_V3) + self._set_fake_env() + + # Patch os.environ to avoid required auth info. + def _set_fake_env(self): + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + + def _script_keystone_client(self): + fakes.script_keystone_client() - @httpretty.activate def test_resource_type_template_yaml(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"heat_template_version": "2013-05-23", "parameters": {}, "resources": {}, @@ -1694,9 +1672,8 @@ class ShellTestResourceTypes(ShellBase): for r in required: self.assertRegexpMatches(show_text, r) - @httpretty.activate def test_resource_type_template_json(self): - self.register_keystone_auth_fixture() + self._script_keystone_client() resp_dict = {"AWSTemplateFormatVersion": "2013-05-23", "Parameters": {}, "Resources": {}, @@ -1728,18 +1705,23 @@ class ShellTestResourceTypes(ShellBase): class ShellTestBuildInfo(ShellBase): - def setUp(self): super(ShellTestBuildInfo, self).setUp() self._set_fake_env() def _set_fake_env(self): '''Patch os.environ to avoid required auth info.''' - self.set_fake_env(FAKE_ENV_KEYSTONE_V2) - @httpretty.activate + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + def test_build_info(self): - self.register_keystone_auth_fixture() + fakes.script_keystone_client() resp_dict = { 'build_info': { 'api': {'revision': 'api_revision'}, @@ -1788,11 +1770,8 @@ class ShellTestToken(ShellTestUserPass): } self.set_fake_env(fake_env) - -class ShellTestUserPassKeystoneV3(ShellTestUserPass): - - def _set_fake_env(self): - self.set_fake_env(FAKE_ENV_KEYSTONE_V3) + def _script_keystone_client(self): + fakes.script_keystone_client(token=self.token) class ShellTestStandaloneToken(ShellTestUserPass): @@ -1817,9 +1796,11 @@ class ShellTestStandaloneToken(ShellTestUserPass): } self.set_fake_env(fake_env) - @httpretty.activate + def _script_keystone_client(self): + # The StanaloneMode shouldn't need any keystoneclient stubbing + pass + def test_bad_template_file(self): - self.register_keystone_auth_fixture() failed_msg = 'Error parsing template ' with tempfile.NamedTemporaryFile() as bad_json_file: diff --git a/heatclient/v1/client.py b/heatclient/v1/client.py index b5e34858..2ce73023 100644 --- a/heatclient/v1/client.py +++ b/heatclient/v1/client.py @@ -36,7 +36,7 @@ class Client(object): def __init__(self, *args, **kwargs): """Initialize a new client for the Heat v1 API.""" - self.http_client = http._construct_http_client(*args, **kwargs) + self.http_client = http.HTTPClient(*args, **kwargs) self.stacks = stacks.StackManager(self.http_client) self.resources = resources.ResourceManager(self.http_client) self.resource_types = resource_types.ResourceTypeManager( diff --git a/test-requirements.txt b/test-requirements.txt index b9f30c02..0fe69885 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -3,7 +3,6 @@ discover fixtures>=0.3.14 # Hacking already pins down pep8, pyflakes and flake8 hacking>=0.8.0,<0.9 -httpretty>=0.8.0,!=0.8.1,!=0.8.2 mock>=1.0 mox3>=0.7.0 sphinx>=1.1.2,!=1.2.0,<1.3