Commit db03f805 authored by Stavros Sachtouris's avatar Stavros Sachtouris
Browse files

Make authentication lazy

Refs: #4300

Authentication (a.k.a. POST /tokens) is performed only if needed, therefore a
syntax query will not request for authentication.

A new method is introduced in kamaki.cli: init_chached_authenticator. This
method authenticated the resolved URL and TOKEN(s).

Until now, this functionality was part of the _init_session method located at
kamaki.cli entry point. Now, this method call has been pushed down.

In case of an interactive shell, the method is called during the shell setup
In case of a one_command, the method is called right before a new executable
command is initialized. This also means that a non-executable command name
space will not cause the execution of init_cached_authenticator.
parent 7f869771
...@@ -229,7 +229,7 @@ def _check_config_version(cnf): ...@@ -229,7 +229,7 @@ def _check_config_version(cnf):
def _init_session(arguments, is_non_API=False): def _init_session(arguments, is_non_API=False):
""" """
:returns: (AuthCachedClient, str) authenticator and cloud name :returns: cloud name
""" """
global _help global _help
_help = arguments['help'].value _help = arguments['help'].value
...@@ -245,7 +245,7 @@ def _init_session(arguments, is_non_API=False): ...@@ -245,7 +245,7 @@ def _init_session(arguments, is_non_API=False):
_setup_logging(_silent, _debug, _verbose, _include) _setup_logging(_silent, _debug, _verbose, _include)
if _help or is_non_API: if _help or is_non_API:
return None, None return None
_check_config_version(_cnf.value) _check_config_version(_cnf.value)
...@@ -299,32 +299,34 @@ def _init_session(arguments, is_non_API=False): ...@@ -299,32 +299,34 @@ def _init_session(arguments, is_non_API=False):
'Set a %s for cloud %s:' % (term.upper(), cloud), 'Set a %s for cloud %s:' % (term.upper(), cloud),
' kamaki config set cloud.%s.%s <%s>' % ( ' kamaki config set cloud.%s.%s <%s>' % (
cloud, term, term.upper())]) cloud, term, term.upper())])
return cloud
def init_cached_authenticator(url, tokens, config_module, logger):
try: try:
auth_base = None auth_base = None
for token in reversed(auth_args['token'].split()): for token in reversed(tokens):
try: try:
if auth_base: if auth_base:
auth_base.authenticate(token) auth_base.authenticate(token)
else: else:
auth_base = AuthCachedClient( auth_base = AuthCachedClient(url, tokens)
auth_args['url'], auth_args['token'])
from kamaki.cli.commands import _command_init from kamaki.cli.commands import _command_init
fake_cmd = _command_init(arguments) fake_cmd = _command_init(dict(config=config_module))
fake_cmd.client = auth_base fake_cmd.client = auth_base
fake_cmd._set_log_params() fake_cmd._set_log_params()
fake_cmd._update_max_threads() fake_cmd._update_max_threads()
auth_base.authenticate(token) auth_base.authenticate(token)
except ClientError as ce: except ClientError as ce:
if ce.status in (401, ): if ce.status in (401, ):
kloger.warning( logger.warning(
'WARNING: Failed to authorize token %s' % token) 'WARNING: Failed to authenticate token %s' % token)
else: else:
raise raise
return auth_base, cloud return auth_base
except AssertionError as ae: except AssertionError as ae:
kloger.warning('WARNING: Failed to load authenticator [%s]' % ae) logger.warning('WARNING: Failed to load authenticator [%s]' % ae)
return None, cloud return None
def _load_spec_module(spec, arguments, module): def _load_spec_module(spec, arguments, module):
...@@ -475,17 +477,21 @@ def set_command_params(parameters): ...@@ -475,17 +477,21 @@ def set_command_params(parameters):
# CLI Choice: # CLI Choice:
def run_one_cmd(exe_string, parser, auth_base, cloud): def run_one_cmd(exe_string, parser, cloud):
global _history global _history
_history = History( _history = History(parser.arguments['config'].get_global('history_file'))
parser.arguments['config'].get_global('history_file'))
_history.add(' '.join([exe_string] + argv[1:])) _history.add(' '.join([exe_string] + argv[1:]))
from kamaki.cli import one_command from kamaki.cli import one_command
one_command.run(auth_base, cloud, parser, _help) one_command.run(cloud, parser, _help)
def run_shell(exe_string, parser, auth_base, cloud): def run_shell(exe_string, parser, cloud):
from command_shell import _init_shell from command_shell import _init_shell
global kloger
_cnf = parser.arguments['config']
auth_base = init_cached_authenticator(
_cnf.get_cloud(cloud, 'url'), _cnf.get_cloud(cloud, 'token').split(),
_cnf, kloger)
try: try:
username, userid = ( username, userid = (
auth_base.user_term('name'), auth_base.user_term('id')) auth_base.user_term('name'), auth_base.user_term('id'))
...@@ -514,27 +520,27 @@ def main(): ...@@ -514,27 +520,27 @@ def main():
if parser.arguments['version'].value: if parser.arguments['version'].value:
exit(0) exit(0)
log_file = parser.arguments['config'].get_global('log_file') _cnf = parser.arguments['config']
log_file = _cnf.get_global('log_file')
if log_file: if log_file:
logger.set_log_filename(log_file) logger.set_log_filename(log_file)
global filelog global filelog
filelog = logger.add_file_logger(__name__.split('.')[0]) filelog = logger.add_file_logger(__name__.split('.')[0])
filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv)) filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv))
auth_base, cloud = _init_session(parser.arguments, is_non_API(parser)) cloud = _init_session(parser.arguments, is_non_API(parser))
from kamaki.cli.utils import suggest_missing from kamaki.cli.utils import suggest_missing
global _colors global _colors
exclude = ['ansicolors'] if not _colors == 'on' else [] exclude = ['ansicolors'] if not _colors == 'on' else []
suggest_missing(exclude=exclude) suggest_missing(exclude=exclude)
if parser.unparsed: if parser.unparsed:
run_one_cmd(exe, parser, auth_base, cloud) run_one_cmd(exe, parser, cloud)
elif _help: elif _help:
parser.parser.print_help() parser.parser.print_help()
_groups_help(parser.arguments) _groups_help(parser.arguments)
else: else:
run_shell(exe, parser, auth_base, cloud) run_shell(exe, parser, cloud)
except CLIError as err: except CLIError as err:
print_error_message(err) print_error_message(err)
if _debug: if _debug:
......
...@@ -31,10 +31,10 @@ ...@@ -31,10 +31,10 @@
# interpreted as representing official policies, either expressed # interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.command # or implied, of GRNET S.A.command
from kamaki.cli import get_command_group, set_command_params from kamaki.cli import (
from kamaki.cli import print_subcommands_help, exec_cmd, update_parser_help get_command_group, set_command_params, print_subcommands_help, exec_cmd,
from kamaki.cli import _groups_help, _load_spec_module update_parser_help, _groups_help, _load_spec_module,
from kamaki.cli import kloger init_cached_authenticator, kloger)
from kamaki.cli.errors import CLIUnknownCommand from kamaki.cli.errors import CLIUnknownCommand
...@@ -55,7 +55,7 @@ def _get_best_match_from_cmd_tree(cmd_tree, unparsed): ...@@ -55,7 +55,7 @@ def _get_best_match_from_cmd_tree(cmd_tree, unparsed):
return None return None
def run(auth_base, cloud, parser, _help): def run(cloud, parser, _help):
group = get_command_group(list(parser.unparsed), parser.arguments) group = get_command_group(list(parser.unparsed), parser.arguments)
if not group: if not group:
parser.parser.print_help() parser.parser.print_help()
...@@ -68,7 +68,8 @@ def run(auth_base, cloud, parser, _help): ...@@ -68,7 +68,8 @@ def run(auth_base, cloud, parser, _help):
global _best_match global _best_match
_best_match = [] _best_match = []
group_spec = parser.arguments['config'].get('global', '%s_cli' % group) _cnf = parser.arguments['config']
group_spec = _cnf.get('global', '%s_cli' % group)
spec_module = _load_spec_module(group_spec, parser.arguments, '_commands') spec_module = _load_spec_module(group_spec, parser.arguments, '_commands')
if spec_module is None: if spec_module is None:
raise CLIUnknownCommand( raise CLIUnknownCommand(
...@@ -98,9 +99,11 @@ def run(auth_base, cloud, parser, _help): ...@@ -98,9 +99,11 @@ def run(auth_base, cloud, parser, _help):
exit(0) exit(0)
cls = cmd.cmd_class cls = cmd.cmd_class
auth_base = init_cached_authenticator(
_cnf.get_cloud(cloud, 'url'), _cnf.get_cloud(cloud, 'token').split(),
_cnf, kloger)
executable = cls(parser.arguments, auth_base, cloud) executable = cls(parser.arguments, auth_base, cloud)
parser.update_arguments(executable.arguments) parser.update_arguments(executable.arguments)
#parsed, unparsed = parse_known_args(parser, executable.arguments)
for term in _best_match: for term in _best_match:
parser.unparsed.remove(term) parser.unparsed.remove(term)
exec_cmd(executable, parser.unparsed, parser.parser.print_help) exec_cmd(executable, parser.unparsed, parser.parser.print_help)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment