Commit 32aad5c5 authored by Stavros Sachtouris's avatar Stavros Sachtouris

Merge branch 'feature-errors' into develop

parents f2a310a3 285d7238
include README.rst COPYRIGHT
recursive-include docs *
prune docs/_build
......@@ -44,6 +44,10 @@ from argparse import RawDescriptionHelpFormatter
try:
from progress.bar import ShadyBar as KamakiProgressBar
except ImportError:
try:
from progress.bar import Bar as KamakiProgressBar
except ImportError:
pass
# progress not installed - pls, pip install progress
pass
......
......@@ -38,6 +38,7 @@ recvlog = logging.getLogger('clients.recv')
class _command_init(object):
def __init__(self, arguments={}):
if hasattr(self, 'arguments'):
arguments.update(self.arguments)
......@@ -48,6 +49,21 @@ class _command_init(object):
except KeyError:
pass
def _safe_progress_bar(self, msg, arg='progress_bar'):
"""Try to get a progress bar, but do not raise errors"""
try:
progress_bar = self.arguments[arg]
gen = progress_bar.get_generator(msg)
except Exception:
return (None, None)
return (progress_bar, gen)
def _safe_progress_bar_finish(self, progress_bar):
try:
progress_bar.finish()
except Exception:
pass
def __getitem__(self, argterm):
"""
:param argterm: (str) the name/label of an argument in self.arguments
......
......@@ -32,10 +32,9 @@
# or implied, of GRNET S.A.command
from kamaki.cli import command
from kamaki.clients.astakos import AstakosClient, ClientError
from kamaki.clients.astakos import AstakosClient
from kamaki.cli.utils import print_dict
from kamaki.cli.errors import raiseCLIError
from kamaki.cli.commands import _command_init
from kamaki.cli.commands import _command_init, errors
from kamaki.cli.command_tree import CommandTree
astakos_cmds = CommandTree('astakos', 'Astakos API commands')
......@@ -43,15 +42,19 @@ _commands = [astakos_cmds]
class _astakos_init(_command_init):
def main(self):
@errors.generic.all
@errors.astakos.load
def _run(self):
token = self.config.get('astakos', 'token')\
or self.config.get('global', 'token')
base_url = self.config.get('astakos', 'url')\
or self.config.get('global', 'url')
if base_url is None:
raiseCLIError(None, 'Missing astakos server URL')
self.client = AstakosClient(base_url=base_url, token=token)
def main(self):
self._run
@command(astakos_cmds)
class astakos_authenticate(_astakos_init):
......@@ -63,18 +66,12 @@ class astakos_authenticate(_astakos_init):
Token can also be provided as a parameter
"""
def main(self, custom_token=None):
super(self.__class__, self).main()
try:
reply = self.client.authenticate(custom_token)
except ClientError as ce:
if (ce.status == 401):
raiseCLIError(ce,
details=['See if token is set: /config get token',
'If not, set a token:',
' 1.(permanent): /config set token <token>',
' 2.(temporary): rerun with <token> parameter'])
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
@errors.generic.all
@errors.astakos.authenticate
def _run(self, custom_token=None):
super(self.__class__, self)._run()
reply = self.client.authenticate(custom_token)
print_dict(reply)
def main(self, custom_token=None):
self._run(custom_token)
......@@ -33,7 +33,7 @@
from kamaki.cli import command
from kamaki.cli.argument import FlagArgument
from kamaki.cli.commands import _command_init
from kamaki.cli.commands import _command_init, errors
from kamaki.cli.command_tree import CommandTree
config_cmds = CommandTree('config', 'Configuration commands')
......@@ -59,27 +59,34 @@ class config_list(_command_init):
A: Default options remain if not explicitly replaced or deleted
"""
def main(self):
@errors.generic.all
def _run(self):
for section in sorted(self.config.sections()):
items = self.config.items(section)
for key, val in sorted(items):
print('%s.%s = %s' % (section, key, val))
def main(self):
self._run()
@command(config_cmds)
class config_get(_command_init):
"""Show a configuration option
"""
"""Show a configuration option"""
__doc__ += about_options
def main(self, option):
@errors.generic.all
def _run(self, option):
section, sep, key = option.rpartition('.')
section = section or 'global'
value = self.config.get(section, key)
if value:
print(value)
def main(self, option):
self._run(option)
@command(config_cmds)
class config_set(_command_init):
......@@ -87,13 +94,17 @@ class config_set(_command_init):
__doc__ += about_options
def main(self, option, value):
@errors.generic.all
def _run(self, option, value):
section, sep, key = option.rpartition('.')
section = section or 'global'
self.config.set(section, key, value)
self.config.write()
self.config.reload()
def main(self, option, value):
self._run(option, value)
@command(config_cmds)
class config_delete(_command_init):
......@@ -104,13 +115,17 @@ class config_delete(_command_init):
arguments = dict(
default=FlagArgument(
'Remove default value as well (persists until end of sesion)',
'Remove default value as well (persists until end of session)',
'--default')
)
def main(self, option):
@errors.generic.all
def _run(self, option):
section, sep, key = option.rpartition('.')
section = section or 'global'
self.config.remove_option(section, key, self['default'])
self.config.write()
self.config.reload()
def main(self, option):
self._run(option)
This diff is collapsed.
This diff is collapsed.
......@@ -38,9 +38,9 @@ from kamaki.cli.argument import IntArgument, ValueArgument
from kamaki.cli.argument import ArgumentParseManager
from kamaki.cli.history import History
from kamaki.cli import command
from kamaki.cli.commands import _command_init
from kamaki.cli.commands import _command_init, errors
from kamaki.cli import exec_cmd, print_error_message
from kamaki.cli.errors import CLIError, CLISyntaxError, raiseCLIError
from kamaki.cli.errors import CLIError, raiseCLIError
from kamaki.cli.utils import split_input
from kamaki.clients import ClientError
......@@ -72,9 +72,14 @@ def _get_num_list(num_str):
class _init_history(_command_init):
def main(self):
@errors.generic.all
@errors.history.init
def _run(self):
self.history = History(self.config.get('history', 'file'))
def main(self):
self._run()
@command(history_cmds)
class history_show(_init_history):
......@@ -98,8 +103,8 @@ class history_show(_init_history):
match=ValueArgument('show lines that match given terms', '--match')
)
def main(self, *cmd_ids):
super(self.__class__, self).main()
@errors.generic.all
def _run(self, *cmd_ids):
ret = self.history.get(match_terms=self['match'], limit=self['limit'])
if not cmd_ids:
......@@ -116,18 +121,25 @@ class history_show(_init_history):
if cur_id:
print(ret[cur_id - (1 if cur_id > 0 else 0)][:-1])
except IndexError as e2:
print('LA %s LA' % self.__doc__)
raiseCLIError(e2, 'Command id out of 1-%s range' % len(ret))
def main(self, *cmd_ids):
super(self.__class__, self)._run()
self._run(*cmd_ids)
@command(history_cmds)
class history_clean(_init_history):
"""Clean up history (permanent)"""
def main(self):
super(self.__class__, self).main()
@errors.generic.all
def _run(self):
self.history.clean()
def main(self):
super(self.__class__, self)._run()
self._run()
@command(history_cmds)
class history_run(_init_history):
......@@ -149,6 +161,7 @@ class history_run(_init_history):
super(self.__class__, self).__init__(arguments)
self._cmd_tree = cmd_tree
@errors.generic.all
def _run_from_line(self, line):
terms = split_input(line)
cmd, args = self._cmd_tree.find_best_match(terms)
......@@ -169,17 +182,16 @@ class history_run(_init_history):
print('Execution of [ %s ] failed' % line)
print('\t%s' % e)
@errors.generic.all
@errors.history._get_cmd_ids
def _get_cmd_ids(self, cmd_ids):
if not cmd_ids:
raise CLISyntaxError('Usage: <id1|id1-id2> [id3|id3-id4] ...',
details=self.__doc__.split('\n'))
cmd_id_list = []
for cmd_str in cmd_ids:
cmd_id_list += _get_num_list(cmd_str)
return cmd_id_list
def main(self, *command_ids):
super(self.__class__, self).main()
@errors.generic.all
def _run(self, *command_ids):
cmd_list = self._get_cmd_ids(command_ids)
for cmd_id in cmd_list:
r = self.history.retrieve(cmd_id)
......@@ -190,3 +202,7 @@ class history_run(_init_history):
if self._cmd_tree:
r = r[len('kamaki '):-1] if r.startswith('kamaki ') else r[:-1]
self._run_from_line(r)
def main(self, *command_ids):
super(self.__class__, self)._run()
self._run(*command_ids)
......@@ -33,14 +33,12 @@
from kamaki.cli import command
from kamaki.cli.command_tree import CommandTree
from kamaki.cli.errors import raiseCLIError
from kamaki.cli.utils import print_dict, print_items
from kamaki.clients.image import ImageClient, ClientError
from kamaki.clients.image import ImageClient
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
from kamaki.cli.argument import IntArgument
from kamaki.cli.commands.cyclades_cli import _init_cyclades
from kamaki.cli.commands.cyclades_cli import raise_if_connection_error
from kamaki.cli.commands import _command_init
from kamaki.cli.commands import _command_init, errors
image_cmds = CommandTree(
......@@ -53,17 +51,18 @@ about_image_id = ['To see a list of available image ids: /image list']
class _init_image(_command_init):
@errors.generic.all
def _run(self):
token = self.config.get('image', 'token')\
or self.config.get('compute', 'token')\
or self.config.get('global', 'token')
base_url = self.config.get('image', 'url')\
or self.config.get('compute', 'url')\
or self.config.get('global', 'url')
self.client = ImageClient(base_url=base_url, token=token)
def main(self):
try:
token = self.config.get('image', 'token')\
or self.config.get('compute', 'token')\
or self.config.get('global', 'token')
base_url = self.config.get('image', 'url')\
or self.config.get('compute', 'url')\
or self.config.get('global', 'url')
self.client = ImageClient(base_url=base_url, token=token)
except Exception as err:
raiseCLIError(err)
self._run()
@command(image_cmds)
......@@ -90,8 +89,10 @@ class image_public(_init_image):
'--more')
)
def main(self):
super(self.__class__, self).main()
@errors.generic.all
@errors.cyclades.connection
def _run(self):
super(self.__class__, self)._run()
filters = {}
for arg in set([
'container_format',
......@@ -105,13 +106,7 @@ class image_public(_init_image):
order = self['order']
detail = self['detail']
try:
images = self.client.list_public(detail, filters, order)
except ClientError as ce:
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
images = self.client.list_public(detail, filters, order)
if self['more']:
print_items(
images,
......@@ -126,6 +121,10 @@ class image_public(_init_image):
else:
print_items(images, title=('name',), with_enumeration=True)
def main(self):
super(self.__class__, self)._run()
self._run()
@command(image_cmds)
class image_meta(_init_image):
......@@ -136,21 +135,17 @@ class image_meta(_init_image):
- image os properties (os, fs, etc.)
"""
def main(self, image_id):
super(self.__class__, self).main()
try:
image = self.client.get_meta(image_id)
except ClientError as ce:
if ce.status == 404:
raiseCLIError(ce,
'No image with id %s found' % image_id,
details=about_image_id)
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id):
image = self.client.get_meta(image_id)
print_dict(image)
def main(self, image_id):
super(self.__class__, self)._run()
self._run(image_id=image_id)
@command(image_cmds)
class image_register(_init_image):
......@@ -172,8 +167,9 @@ class image_register(_init_image):
update=FlagArgument('update existing image properties', '--update')
)
def main(self, name, location):
super(self.__class__, self).main()
@errors.generic.all
@errors.plankton.connection
def _run(self, name, location):
if not location.startswith('pithos://'):
account = self.config.get('store', 'account') \
or self.config.get('global', 'account')
......@@ -199,106 +195,91 @@ class image_register(_init_image):
]).intersection(self.arguments):
params[key] = self[key]
try:
properties = self['properties']
if self['update']:
self.client.reregister(location, name, params, properties)
else:
self.client.register(name, location, params, properties)
except ClientError as ce:
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
if self['update']:
self.client.reregister(location, name, params, properties)
else:
self.client.register(name, location, params, properties)
def main(self, name, location):
super(self.__class__, self)._run()
self._run(name, location)
@command(image_cmds)
class image_members(_init_image):
"""Get image members"""
def main(self, image_id):
super(self.__class__, self).main()
try:
members = self.client.list_members(image_id)
except ClientError as ce:
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id):
members = self.client.list_members(image_id)
print_items(members)
def main(self, image_id):
super(self.__class__, self)._run()
self._run(image_id=image_id)
@command(image_cmds)
class image_shared(_init_image):
"""List images shared by a member"""
def main(self, member):
super(self.__class__, self).main()
try:
images = self.client.list_shared(member)
except ClientError as ce:
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
@errors.generic.all
@errors.plankton.connection
def _run(self, member):
images = self.client.list_shared(member)
print_items(images)
def main(self, member):
super(self.__class__, self)._run()
self._run(member)
@command(image_cmds)
class image_addmember(_init_image):
"""Add a member to an image"""
def main(self, image_id, member):
super(self.__class__, self).main()
try:
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id=None, member=None):
self.client.add_member(image_id, member)
except ClientError as ce:
if ce.status == 404:
raiseCLIError(ce,
'No image with id %s found' % image_id,
details=about_image_id)
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
def main(self, image_id, member):
super(self.__class__, self)._run()
self._run(image_id=image_id, member=member)
@command(image_cmds)
class image_delmember(_init_image):
"""Remove a member from an image"""
def main(self, image_id, member):
super(self.__class__, self).main()
try:
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id=None, member=None):
self.client.remove_member(image_id, member)
except ClientError as ce:
if ce.status == 404:
raiseCLIError(ce,
'No image with id %s found' % image_id,
details=about_image_id)
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
def main(self, image_id, member):
super(self.__class__, self)._run()
self._run(image_id=image_id, member=member)
@command(image_cmds)
class image_setmembers(_init_image):
"""Set the members of an image"""
def main(self, image_id, *member):
super(self.__class__, self).main()
try:
self.client.set_members(image_id, member)
except ClientError as ce:
if ce.status == 404:
raiseCLIError(ce,
'No image with id %s found' % image_id,
details=about_image_id)
raise_if_connection_error(ce, base_url='image.url')
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id, members):
self.client.set_members(image_id, members)
def main(self, image_id, *members):
super(self.__class__, self)._run()
self._run(image_id=image_id, members=members)
@command(image_cmds)
......@@ -318,155 +299,121 @@ class image_list(_init_cyclades):
if 'metadata' in img:
img['metadata'] = img['metadata']['values']
@errors.generic.all
@errors.cyclades.connection
def _run(self):
images = self.client.list_images(self['detail'])
if self['detail']:
self._make_results_pretty(images)
if self['more']:
print_items(images,
page_size=self['limit'] if self['limit'] else 10)
elif self['limit']:
print_items(images[:self['limit']])
else:
print_items(images)
def main(self):
super(self.__class__, self).main()
try:
images = self.client.list_images(self['detail'])
if self['detail']:
self._make_results_pretty(images)
if self['more']:
print_items(images,
page_size=self['limit'] if self['limit'] else 10)
elif self['limit']:
print_items(images[:self['limit']])
else:
print_items(images)
except ClientError as ce:
raise_if_connection_error(ce)
raiseCLIError(ce)
except Exception as err:
raiseCLIError(err)
super(self.__class__, self)._run()
self._run()
@command(image_cmds)
class image_info(_init_cyclades):
"""Get detailed information on an image"""
@classmethod
def _make_results_pretty(self, image):