import logging
from sys import argv, exit, stdout
-from os.path import basename
+from os.path import basename, exists
from inspect import getargspec
from kamaki.cli.argument import ArgumentParseManager
kloger = logger.get_logger(__name__)
-def _init_session(arguments):
+def _check_config_version(cnf):
+ guess = cnf.guess_version()
+ if exists(cnf.path) and guess < 0.9:
+ print('Config file format version >= 9.0 is required')
+ print('Configuration file: %s' % cnf.path)
+ print('but kamaki can fix this:')
+ print('Calculating changes while preserving information')
+ lost_terms = cnf.rescue_old_file()
+ print('... DONE')
+ if lost_terms:
+ print 'The following information will NOT be preserved:'
+ print '\t', '\n\t'.join(lost_terms)
+ print('Kamaki is ready to convert the config file to version 3.0')
+ stdout.write('Create (overwrite) file %s ? [y/N] ' % cnf.path)
+ from sys import stdin
+ reply = stdin.readline()
+ if reply in ('Y\n', 'y\n'):
+ cnf.write()
+ print('... DONE')
+ else:
+ print('... ABORTING')
+ raise CLIError(
+ 'Invalid format for config file %s' % cnf.path,
+ importance=3, details=[
+ 'Please, update config file to v3.0',
+ 'For automatic conversion, rerun and say Y'])
+
+
+def _init_session(arguments, is_non_API=False):
+ """
+ :returns: (AuthCachedClient, str) authenticator and cloud name
+ """
global _help
_help = arguments['help'].value
global _debug
_include = arguments['include'].value
global _verbose
_verbose = arguments['verbose'].value
+ _cnf = arguments['config']
+
+ if _help or is_non_API:
+ return None, None
+
+ _check_config_version(_cnf.value)
+
global _colors
- _colors = arguments['config'].get('global', 'colors')
+ _colors = _cnf.value.get_global('colors')
if not (stdout.isatty() and _colors == 'on'):
from kamaki.cli.utils import remove_colors
remove_colors()
_silent = arguments['silent'].value
_setup_logging(_silent, _debug, _verbose, _include)
+ cloud = arguments['cloud'].value or _cnf.value.get(
+ 'global', 'default_cloud')
+ if not cloud:
+ num_of_clouds = len(_cnf.value.keys('cloud'))
+ if num_of_clouds == 1:
+ cloud = _cnf.value.keys('cloud')[0]
+ elif num_of_clouds > 1:
+ raise CLIError(
+ 'Found %s clouds but none of them is set as default' % (
+ num_of_clouds),
+ importance=2, details=[
+ 'Please, choose one of the following cloud names:',
+ ', '.join(_cnf.value.keys('cloud')),
+ 'To see all cloud settings:',
+ ' kamaki config get cloud.<cloud name>',
+ 'To set a default cloud:',
+ ' kamaki config set default_cloud <cloud name>',
+ 'To pick a cloud for the current session, use --cloud:',
+ ' kamaki --cloud=<cloud name> ...'])
+ if not cloud in _cnf.value.keys('cloud'):
+ raise CLIError(
+ 'No cloud%s is configured' % ((' "%s"' % cloud) if cloud else ''),
+ importance=3, details=[
+ 'To configure a new cloud "%s", find and set the' % (
+ cloud or '<cloud name>'),
+ 'single authentication URL and token:',
+ ' kamaki config set cloud.%s.url <URL>' % (
+ cloud or '<cloud name>'),
+ ' kamaki config set cloud.%s.token <t0k3n>' % (
+ cloud or '<cloud name>')])
+ auth_args = dict()
+ for term in ('url', 'token'):
+ try:
+ auth_args[term] = _cnf.get_cloud(cloud, term)
+ except KeyError:
+ auth_args[term] = ''
+ if not auth_args[term]:
+ raise CLIError(
+ 'No authentication %s provided for cloud "%s"' % (term, cloud),
+ importance=3, details=[
+ 'Set a %s for cloud %s:' % (term, cloud),
+ ' kamaki config set cloud.%s.%s <%s>' % (
+ cloud, term, term)])
+
+ from kamaki.clients.astakos import AstakosClient as AuthCachedClient
+ try:
+ return AuthCachedClient(auth_args['url'], auth_args['token']), cloud
+ except AssertionError as ae:
+ kloger.warning('WARNING: Failed to load authenticator [%s]' % ae)
+ return None, cloud
+
def _load_spec_module(spec, arguments, module):
- spec_name = arguments['config'].get(spec, 'cli')
- if spec_name is None:
+ if not spec:
return None
pkg = None
for location in cmd_spec_locations:
- location += spec_name if location == '' else '.%s' % spec_name
+ location += spec if location == '' else '.%s' % spec
try:
pkg = __import__(location, fromlist=[module])
return pkg
- except ImportError:
+ except ImportError as ie:
continue
+ if not pkg:
+ kloger.debug('Loading cmd grp %s failed: %s' % (spec, ie))
return pkg
global _debug
global kloger
descriptions = {}
- for spec in arguments['config'].get_groups():
+ for cmd_group, spec in arguments['config'].get_cli_specs():
pkg = _load_spec_module(spec, arguments, '_commands')
if pkg:
- cmds = None
- try:
- _cnf = arguments['config']
- cmds = [cmd for cmd in getattr(pkg, '_commands') if _cnf.get(
- cmd.name, 'cli')]
- except AttributeError:
- if _debug:
- kloger.warning('No description for %s' % spec)
+ cmds = getattr(pkg, '_commands')
try:
for cmd in cmds:
descriptions[cmd.name] = cmd.description
except TypeError:
if _debug:
- kloger.warning('no cmd specs in module %s' % spec)
+ kloger.warning(
+ 'No cmd description for module %s' % cmd_group)
elif _debug:
- kloger.warning('Loading of %s cmd spec failed' % spec)
+ kloger.warning('Loading of %s cmd spec failed' % cmd_group)
print('\nOptions:\n - - - -')
print_dict(descriptions)
def _load_all_commands(cmd_tree, arguments):
_cnf = arguments['config']
- specs = [spec for spec in _cnf.get_groups() if _cnf.get(spec, 'cli')]
- for spec in specs:
+ for cmd_group, spec in _cnf.get_cli_specs():
try:
spec_module = _load_spec_module(spec, arguments, '_commands')
spec_commands = getattr(spec_module, '_commands')
except AttributeError:
if _debug:
global kloger
- kloger.warning('No valid description for %s' % spec)
+ kloger.warning('No valid description for %s' % cmd_group)
continue
for spec_tree in spec_commands:
- if spec_tree.name == spec:
+ if spec_tree.name == cmd_group:
cmd_tree.add_tree(spec_tree)
break
errmsg = red(errmsg)
stdout.write(errmsg)
for errmsg in cli_err.details:
- print('| %s' % errmsg)
+ print('| %s' % errmsg)
def exec_cmd(instance, cmd_args, help_method):
# CLI Choice:
-def run_one_cmd(exe_string, parser):
+def run_one_cmd(exe_string, parser, auth_base, cloud):
global _history
_history = History(
- parser.arguments['config'].get('history', 'file'))
+ parser.arguments['config'].get_global('history_file'))
_history.add(' '.join([exe_string] + argv[1:]))
from kamaki.cli import one_command
- one_command.run(parser, _help)
+ one_command.run(auth_base, cloud, parser, _help)
-def run_shell(exe_string, parser):
+def run_shell(exe_string, parser, auth_base, cloud):
from command_shell import _init_shell
shell = _init_shell(exe_string, parser)
_load_all_commands(shell.cmd_tree, parser.arguments)
- shell.run(parser)
+ shell.run(auth_base, cloud, parser)
+
+
+def is_non_API(parser):
+ nonAPIs = ('history', 'config')
+ for term in parser.unparsed:
+ if not term.startswith('-'):
+ if term in nonAPIs:
+ return True
+ return False
+ return False
def main():
if parser.arguments['version'].value:
exit(0)
- log_file = parser.arguments['config'].get('global', 'log_file')
+ log_file = parser.arguments['config'].get_global('log_file')
if log_file:
logger.set_log_filename(log_file)
global filelog
filelog = logger.add_file_logger(__name__.split('.')[0])
- filelog.info('Log call: %s' % ' '.join(argv))
+ filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv))
- _init_session(parser.arguments)
+ auth_base, cloud = _init_session(parser.arguments, is_non_API(parser))
from kamaki.cli.utils import suggest_missing
- suggest_missing()
+ global _colors
+ exclude = ['ansicolors'] if not _colors == 'on' else []
+ suggest_missing(exclude=exclude)
if parser.unparsed:
- run_one_cmd(exe, parser)
+ run_one_cmd(exe, parser, auth_base, cloud)
elif _help:
parser.parser.print_help()
_groups_help(parser.arguments)
else:
- run_shell(exe, parser)
+ run_shell(exe, parser, auth_base, cloud)
except CLIError as err:
print_error_message(err)
if _debug: