CLI support of Keystone openrc
Add support of the standard openrc env vars to the CLI so that a token will be automatically generated and the Drydock API endpoint will be sourced from the Keystone catalogue. - Use click to allow env or cli based keystone env Change-Id: I10a48d509c0b90670af07870a1ae4d31525b4a3b
This commit is contained in:
parent
27d54b3c46
commit
fe527999aa
@ -18,6 +18,7 @@ from urllib.parse import urlparse
|
||||
|
||||
import click
|
||||
from drydock_provisioner.drydock_client.session import DrydockSession
|
||||
from drydock_provisioner.drydock_client.session import KeystoneClient
|
||||
from drydock_provisioner.drydock_client.client import DrydockClient
|
||||
from .design import commands as design
|
||||
from .part import commands as part
|
||||
@ -27,32 +28,43 @@ from .node import commands as node
|
||||
@click.group()
|
||||
@click.option(
|
||||
'--debug/--no-debug', help='Enable or disable debugging', default=False)
|
||||
# Supported Environment Variables
|
||||
@click.option(
|
||||
'--token',
|
||||
'-t',
|
||||
help='The auth token to be used',
|
||||
default=lambda: os.environ.get('DD_TOKEN', ''))
|
||||
'--os_project_domain_name',
|
||||
envvar='OS_PROJECT_DOMAIN_NAME',
|
||||
required=False)
|
||||
@click.option(
|
||||
'--os_user_domain_name', envvar='OS_USER_DOMAIN_NAME', required=False)
|
||||
@click.option('--os_project_name', envvar='OS_PROJECT_NAME', required=False)
|
||||
@click.option('--os_username', envvar='OS_USERNAME', required=False)
|
||||
@click.option('--os_password', envvar='OS_PASSWORD', required=False)
|
||||
@click.option('--os_auth_url', envvar='OS_AUTH_URL', required=False)
|
||||
@click.option(
|
||||
'--os_token',
|
||||
help='The Keystone token to be used',
|
||||
default=lambda: os.environ.get('OS_TOKEN', ''))
|
||||
@click.option(
|
||||
'--url',
|
||||
'-u',
|
||||
help='The url of the running drydock instance',
|
||||
default=lambda: os.environ.get('DD_URL', ''))
|
||||
@click.pass_context
|
||||
def drydock(ctx, debug, token, url):
|
||||
""" Drydock CLI to invoke the running instance of the drydock API
|
||||
"""
|
||||
def drydock(ctx, debug, url, os_project_domain_name, os_user_domain_name, os_project_name,
|
||||
os_username, os_password, os_auth_url, os_token):
|
||||
"""Drydock CLI to invoke the running instance of the drydock API."""
|
||||
if not ctx.obj:
|
||||
ctx.obj = {}
|
||||
|
||||
ctx.obj['DEBUG'] = debug
|
||||
|
||||
if not token:
|
||||
ctx.fail('Error: Token must be specified either by '
|
||||
'--token or DD_TOKEN from the environment')
|
||||
|
||||
if not url:
|
||||
ctx.fail('Error: URL must be specified either by '
|
||||
'--url or DD_URL from the environment')
|
||||
keystone_env = {
|
||||
'project_domain_name': os_project_domain_name,
|
||||
'user_domain_name': os_user_domain_name,
|
||||
'project_name': os_project_name,
|
||||
'username': os_username,
|
||||
'password': os_password,
|
||||
'auth_url': os_auth_url,
|
||||
}
|
||||
|
||||
# setup logging for the CLI
|
||||
# Setup root logger
|
||||
@ -66,18 +78,44 @@ def drydock(ctx, debug, token, url):
|
||||
logger.addHandler(logging_handler)
|
||||
logger.debug('logging for cli initialized')
|
||||
|
||||
try:
|
||||
if not os_token:
|
||||
logger.debug("Generating Keystone session by env vars: %s" % str(keystone_env))
|
||||
ks_sess = KeystoneClient.get_ks_session(**keystone_env)
|
||||
else:
|
||||
logger.debug("Generating Keystone session by explicit token: %s" % os_token)
|
||||
ks_sess = KeystoneClient.get_ks_session(token=os_token)
|
||||
KeystoneClient.get_token(ks_sess=ks_sess)
|
||||
except Exception as ex:
|
||||
logger.debug("Exception getting Keystone session.", exc_info=ex)
|
||||
ctx.fail('Error: Unable to authenticate with Keystone')
|
||||
return
|
||||
|
||||
try:
|
||||
if not url:
|
||||
url = KeystoneClient.get_endpoint('physicalprovisioner', ks_sess=ks_sess)
|
||||
except Exception as ex:
|
||||
logger.debug("Exception getting Drydock endpoint.", exc_info=ex)
|
||||
ctx.fail('Error: Unable to discover Drydock API URL')
|
||||
|
||||
# setup the drydock client using the passed parameters.
|
||||
url_parse_result = urlparse(url)
|
||||
logger.debug(url_parse_result)
|
||||
|
||||
if not os_token:
|
||||
token = KeystoneClient.get_token(ks_sess=ks_sess)
|
||||
logger.debug("Creating Drydock client with token %s." % token)
|
||||
else:
|
||||
token = os_token
|
||||
|
||||
if not url_parse_result.scheme:
|
||||
ctx.fail('URL must specify a scheme and hostname, optionally a port')
|
||||
ctx.obj['CLIENT'] = DrydockClient(
|
||||
DrydockSession(
|
||||
scheme=url_parse_result.scheme,
|
||||
host=url_parse_result.netloc,
|
||||
host=url_parse_result.hostname,
|
||||
port=url_parse_result.port,
|
||||
token=token))
|
||||
|
||||
|
||||
drydock.add_command(design.design)
|
||||
drydock.add_command(part.part)
|
||||
drydock.add_command(task.task)
|
||||
|
@ -14,6 +14,8 @@
|
||||
import requests
|
||||
import logging
|
||||
|
||||
from keystoneauth1 import session
|
||||
from keystoneauth1.identity import v3
|
||||
|
||||
class DrydockSession(object):
|
||||
"""
|
||||
@ -40,7 +42,7 @@ class DrydockSession(object):
|
||||
self.base_url = "%s://%s:%s/api/" % (self.scheme, self.host,
|
||||
self.port)
|
||||
else:
|
||||
#assume default port for scheme
|
||||
# assume default port for scheme
|
||||
self.base_url = "%s://%s/api/" % (self.scheme, self.host)
|
||||
|
||||
self.token = token
|
||||
@ -48,7 +50,6 @@ class DrydockSession(object):
|
||||
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
# TODO Add keystone authentication to produce a token for this session
|
||||
def get(self, endpoint, query=None):
|
||||
"""
|
||||
Send a GET request to Drydock.
|
||||
@ -85,3 +86,43 @@ class DrydockSession(object):
|
||||
self.base_url + endpoint, params=query, json=data, timeout=10)
|
||||
|
||||
return resp
|
||||
|
||||
|
||||
class KeystoneClient(object):
|
||||
|
||||
@staticmethod
|
||||
def get_endpoint(endpoint, ks_sess=None, auth_info=None):
|
||||
"""
|
||||
Wraps calls to keystone for lookup of an endpoint by service type
|
||||
:param endpoint: The endpoint to look up
|
||||
:param ks_sess: A keystone session to use for accessing endpoint catalogue
|
||||
:param auth_info: Authentication info to use for building a token if a ``ks_sess`` is not specified
|
||||
:returns: The url string of the endpoint
|
||||
:rtype: str
|
||||
:raises AppError: if the endpoint cannot be resolved
|
||||
"""
|
||||
if ks_sess is None:
|
||||
ks_sess = KeystoneClient.get_ks_session(**auth_info)
|
||||
|
||||
return ks_sess.get_endpoint(interface='internal', service_type=endpoint)
|
||||
|
||||
@staticmethod
|
||||
def get_token(ks_sess=None, auth_info=None):
|
||||
"""
|
||||
Returns the simple token string for a token acquired from keystone
|
||||
|
||||
:param ks_sess: an existing Keystone session to retrieve a token from
|
||||
:param auth_info: dictionary of information required to generate a keystone token
|
||||
"""
|
||||
if ks_sess is None:
|
||||
ks_sess = KeystoneClient.get_ks_session(**auth_info)
|
||||
return ks_sess.get_auth_headers().get('X-Auth-Token')
|
||||
|
||||
@staticmethod
|
||||
def get_ks_session(**kwargs):
|
||||
# Establishes a keystone session
|
||||
if 'token' in kwargs:
|
||||
auth = v3.TokenMethod(token=kwargs.get('token'))
|
||||
else:
|
||||
auth = v3.Password(**kwargs)
|
||||
return session.Session(auth=auth)
|
||||
|
Loading…
Reference in New Issue
Block a user