Merge "Defer auth prompting until it is actually needed"
This commit is contained in:
commit
085bc5255d
@ -16,6 +16,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from os_client_config import config
|
from os_client_config import config
|
||||||
|
from os_client_config import exceptions as occ_exceptions
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -182,6 +183,14 @@ class OSC_Config(config.OpenStackConfig):
|
|||||||
LOG.debug("auth_config_hook(): %s" % config)
|
LOG.debug("auth_config_hook(): %s" % config)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
def load_auth_plugin(self, config):
|
||||||
|
"""Get auth plugin and validate args"""
|
||||||
|
|
||||||
|
loader = self._get_auth_loader(config)
|
||||||
|
config = self._validate_auth(config, loader)
|
||||||
|
auth_plugin = loader.load_from_options(**config['auth'])
|
||||||
|
return auth_plugin
|
||||||
|
|
||||||
def _validate_auth_ksc(self, config, cloud, fixed_argparse=None):
|
def _validate_auth_ksc(self, config, cloud, fixed_argparse=None):
|
||||||
"""Old compatibility hack for OSC, no longer needed/wanted"""
|
"""Old compatibility hack for OSC, no longer needed/wanted"""
|
||||||
return config
|
return config
|
||||||
@ -192,6 +201,8 @@ class OSC_Config(config.OpenStackConfig):
|
|||||||
|
|
||||||
plugin_options = loader.get_options()
|
plugin_options = loader.get_options()
|
||||||
|
|
||||||
|
msgs = []
|
||||||
|
prompt_options = []
|
||||||
for p_opt in plugin_options:
|
for p_opt in plugin_options:
|
||||||
# if it's in config, win, move it and kill it from config dict
|
# if it's in config, win, move it and kill it from config dict
|
||||||
# if it's in config.auth but not in config we're good
|
# if it's in config.auth but not in config we're good
|
||||||
@ -202,6 +213,16 @@ class OSC_Config(config.OpenStackConfig):
|
|||||||
winning_value = self._find_winning_auth_value(
|
winning_value = self._find_winning_auth_value(
|
||||||
p_opt, config['auth'])
|
p_opt, config['auth'])
|
||||||
|
|
||||||
|
# if the plugin tells us that this value is required
|
||||||
|
# then error if it's doesn't exist now
|
||||||
|
if not winning_value and p_opt.required:
|
||||||
|
msgs.append(
|
||||||
|
'Missing value {auth_key}'
|
||||||
|
' required for auth plugin {plugin}'.format(
|
||||||
|
auth_key=p_opt.name, plugin=config.get('auth_type'),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Clean up after ourselves
|
# Clean up after ourselves
|
||||||
for opt in [p_opt.name] + [o.name for o in p_opt.deprecated]:
|
for opt in [p_opt.name] + [o.name for o in p_opt.deprecated]:
|
||||||
opt = opt.replace('-', '_')
|
opt = opt.replace('-', '_')
|
||||||
@ -224,6 +245,13 @@ class OSC_Config(config.OpenStackConfig):
|
|||||||
p_opt.dest not in config['auth'] and
|
p_opt.dest not in config['auth'] and
|
||||||
self._pw_callback is not None
|
self._pw_callback is not None
|
||||||
):
|
):
|
||||||
|
# Defer these until we know all required opts are present
|
||||||
|
prompt_options.append(p_opt)
|
||||||
|
|
||||||
|
if msgs:
|
||||||
|
raise occ_exceptions.OpenStackConfigException('\n'.join(msgs))
|
||||||
|
else:
|
||||||
|
for p_opt in prompt_options:
|
||||||
config['auth'][p_opt.dest] = self._pw_callback(p_opt.prompt)
|
config['auth'][p_opt.dest] = self._pw_callback(p_opt.prompt)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
@ -60,6 +60,26 @@ class ClientManager(clientmanager.ClientManager):
|
|||||||
self._cacert = self.cacert
|
self._cacert = self.cacert
|
||||||
self._insecure = not self.verify
|
self._insecure = not self.verify
|
||||||
|
|
||||||
|
def setup_auth(self):
|
||||||
|
"""Set up authentication"""
|
||||||
|
|
||||||
|
if self._auth_setup_completed:
|
||||||
|
return
|
||||||
|
|
||||||
|
# NOTE(dtroyer): Validate the auth args; this is protected with 'if'
|
||||||
|
# because openstack_config is an optional argument to
|
||||||
|
# CloudConfig.__init__() and we'll die if it was not
|
||||||
|
# passed.
|
||||||
|
if self._cli_options._openstack_config is not None:
|
||||||
|
self._cli_options._openstack_config._pw_callback = \
|
||||||
|
shell.prompt_for_password
|
||||||
|
self._cli_options._auth = \
|
||||||
|
self._cli_options._openstack_config.load_auth_plugin(
|
||||||
|
self._cli_options.config,
|
||||||
|
)
|
||||||
|
|
||||||
|
return super(ClientManager, self).setup_auth()
|
||||||
|
|
||||||
def is_network_endpoint_enabled(self):
|
def is_network_endpoint_enabled(self):
|
||||||
"""Check if the network endpoint is enabled"""
|
"""Check if the network endpoint is enabled"""
|
||||||
|
|
||||||
|
@ -140,12 +140,11 @@ class OpenStackShell(shell.OpenStackShell):
|
|||||||
# First, throw away what has already been done with o-c-c and
|
# First, throw away what has already been done with o-c-c and
|
||||||
# use our own.
|
# use our own.
|
||||||
try:
|
try:
|
||||||
cc = cloud_config.OSC_Config(
|
self.cloud_config = cloud_config.OSC_Config(
|
||||||
override_defaults={
|
override_defaults={
|
||||||
'interface': None,
|
'interface': None,
|
||||||
'auth_type': self._auth_type,
|
'auth_type': self._auth_type,
|
||||||
},
|
},
|
||||||
pw_func=shell.prompt_for_password,
|
|
||||||
)
|
)
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
self.log.critical("Could not read clouds.yaml configuration file")
|
self.log.critical("Could not read clouds.yaml configuration file")
|
||||||
@ -154,9 +153,13 @@ class OpenStackShell(shell.OpenStackShell):
|
|||||||
|
|
||||||
if not self.options.debug:
|
if not self.options.debug:
|
||||||
self.options.debug = None
|
self.options.debug = None
|
||||||
self.cloud = cc.get_one_cloud(
|
|
||||||
|
# NOTE(dtroyer): Need to do this with validate=False to defer the
|
||||||
|
# auth plugin handling to ClientManager.setup_auth()
|
||||||
|
self.cloud = self.cloud_config.get_one_cloud(
|
||||||
cloud=self.options.cloud,
|
cloud=self.options.cloud,
|
||||||
argparse=self.options,
|
argparse=self.options,
|
||||||
|
validate=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Then, re-create the client_manager with the correct arguments
|
# Then, re-create the client_manager with the correct arguments
|
||||||
@ -165,6 +168,33 @@ class OpenStackShell(shell.OpenStackShell):
|
|||||||
api_version=self.api_version,
|
api_version=self.api_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def prepare_to_run_command(self, cmd):
|
||||||
|
"""Set up auth and API versions"""
|
||||||
|
|
||||||
|
# TODO(dtroyer): Move this to osc-lib
|
||||||
|
# NOTE(dtroyer): If auth is not required for a command, force fake
|
||||||
|
# token auth so KSA plugins are happy
|
||||||
|
|
||||||
|
kwargs = {}
|
||||||
|
if not cmd.auth_required:
|
||||||
|
# Build fake token creds to keep ksa and o-c-c hushed
|
||||||
|
kwargs['auth_type'] = 'token_endpoint'
|
||||||
|
kwargs['auth'] = {}
|
||||||
|
kwargs['auth']['token'] = 'x'
|
||||||
|
kwargs['auth']['url'] = 'x'
|
||||||
|
|
||||||
|
# Validate auth options
|
||||||
|
self.cloud = self.cloud_config.get_one_cloud(
|
||||||
|
cloud=self.options.cloud,
|
||||||
|
argparse=self.options,
|
||||||
|
validate=True,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
# Push the updated args into ClientManager
|
||||||
|
self.client_manager._cli_options = self.cloud
|
||||||
|
|
||||||
|
return super(OpenStackShell, self).prepare_to_run_command(cmd)
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
if argv is None:
|
if argv is None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user