diff options
author | Thomas Herve <thomas.herve@enovance.com> | 2014-07-28 18:47:14 +0200 |
---|---|---|
committer | Thomas Herve <thomas.herve@enovance.com> | 2014-07-28 18:58:04 +0200 |
commit | 42c509677046826d6990edf9adeb3dca1ea4c1f0 (patch) | |
tree | 70e751e2581e830cff791a079f1ddc90f9f7f328 /heatclient/shell.py | |
parent | 6eb45625e584f410fdb33d82c63916750650505d (diff) | |
download | python-heatclient-42c509677046826d6990edf9adeb3dca1ea4c1f0.tar.gz |
Revert "Add keystone v3 auth support"
This reverts commit a98c1f3617604c4871263ff9cc986b27f302ef46.
The new usage of session doesn't work with resources or events.
Conflicts:
heatclient/tests/test_shell.py
Closes-Bug: #1349467
Change-Id: Ib5b0db81454abe647aca6461dd7bd5f197267fb8
Diffstat (limited to 'heatclient/shell.py')
-rw-r--r-- | heatclient/shell.py | 482 |
1 files changed, 145 insertions, 337 deletions
diff --git a/heatclient/shell.py b/heatclient/shell.py index bf8fb37..cd00ac6 100644 --- a/heatclient/shell.py +++ b/heatclient/shell.py @@ -18,23 +18,15 @@ from __future__ import print_function import argparse import logging -import sys - import six -import six.moves.urllib.parse as urlparse +import sys -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,52 +34,71 @@ 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. + def get_base_parser(self): + parser = argparse.ArgumentParser( + prog='heat', + description=__doc__.strip(), + epilog='See "heat help COMMAND" ' + 'for help on a specific command.', + add_help=False, + formatter_class=HelpFormatter, + ) + + # Global arguments + parser.add_argument('-h', '--help', + action='store_true', + help=argparse.SUPPRESS) + + parser.add_argument('--version', + action='version', + version=heatclient.__version__, + help="Shows the client version and exits.") + + parser.add_argument('-d', '--debug', + default=bool(utils.env('HEATCLIENT_DEBUG')), + action='store_true', + help='Defaults to env[HEATCLIENT_DEBUG].') + + parser.add_argument('-v', '--verbose', + default=False, action="store_true", + help="Print more verbose output.") + 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.') + 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='<ca-certificate>', + 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('--os-cert', + 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.') - # 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='<ca-certificate-file>', - 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.') + 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', - dest='os_cacert', - help='DEPRECATED! Use --os-cacert.') + 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') parser.add_argument('--os-username', default=utils.env('OS_USERNAME'), @@ -96,61 +107,6 @@ class HeatShell(object): 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].') @@ -163,7 +119,6 @@ class HeatShell(object): 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', @@ -171,7 +126,6 @@ class HeatShell(object): 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', @@ -195,56 +149,6 @@ class HeatShell(object): 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', - description=__doc__.strip(), - epilog='See "heat help COMMAND" ' - 'for help on a specific command.', - add_help=False, - formatter_class=HelpFormatter, - ) - - # Global arguments - parser.add_argument('-h', '--help', - action='store_true', - help=argparse.SUPPRESS) - - parser.add_argument('--version', - action='version', - version=heatclient.__version__, - help="Shows the client version and exits.") - - parser.add_argument('-d', '--debug', - default=bool(utils.env('HEATCLIENT_DEBUG')), - action='store_true', - help='Defaults to env[HEATCLIENT_DEBUG].') - - parser.add_argument('-v', '--verbose', - default=False, action="store_true", - help="Print more verbose output.") - - 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-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,54 +354,45 @@ class HeatShell(object): " env[OS_AUTH_URL]") kwargs = { + '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, - 'cert': args.os_cert, - 'key': args.os_key, - 'timeout': args.api_timeout + 'include_pass': args.include_password } - 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 + + 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, - '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, + 'endpoint_type': args.os_endpoint_type, + 'include_pass': args.include_password } - 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, - '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) |