Commit a0677c5c authored by Stavros Sachtouris's avatar Stavros Sachtouris

Merge classes _optional_output_cmd, _optional_json

New class is called "OptionalOutput"
Old and new classes were/are located at kamaki.cli.cmds
parent c4a6ec1b
......@@ -35,10 +35,9 @@ from kamaki.cli.logger import get_logger
from kamaki.cli.utils import (
print_list, print_dict, print_json, print_items, ask_user, pref_enc,
filter_dicts_by_dict)
from kamaki.cli.argument import FlagArgument, ValueArgument
from kamaki.cli.argument import ValueArgument
from kamaki.cli.errors import CLIInvalidArgument, CLIBaseUrlError
from sys import stdin, stdout, stderr
import codecs
log = get_logger(__name__)
......@@ -91,10 +90,8 @@ class CommandInit(object):
self.required = getattr(self, 'required', None)
if hasattr(self, 'arguments'):
arguments.update(self.arguments)
if isinstance(self, _optional_output_cmd):
if isinstance(self, OptionalOutput):
arguments.update(self.oo_arguments)
if isinstance(self, _optional_json):
arguments.update(self.oj_arguments)
if isinstance(self, _name_filter):
arguments.update(self.nf_arguments)
if isinstance(self, _id_filter):
......@@ -273,7 +270,7 @@ class CommandInit(object):
class OutputFormatArgument(ValueArgument):
"""Accepted output formats: json (default)"""
formats = ('json', )
formats = dict(json=print_json)
def ___init__(self, *args, **kwargs):
super(OutputFormatArgument, self).___init__(*args, **kwargs)
......@@ -285,9 +282,9 @@ class OutputFormatArgument(ValueArgument):
@value.setter
def value(self, newvalue):
if not newvalue:
self._value = self.default
return
elif newvalue.lower() in self.formats:
self._value = newvalue.lower
self._value = newvalue.lower()
else:
raise CLIInvalidArgument(
'Invalid value %s for argument %s' % (
......@@ -295,37 +292,19 @@ class OutputFormatArgument(ValueArgument):
details=['Valid output formats: %s' % ', '.join(self.formats)])
class _optional_output_cmd(object):
class OptionalOutput(object):
oo_arguments = dict(
with_output=FlagArgument('show response headers', ('--with-output')),
json_output=FlagArgument(
'show headers in json (DEPRECATED from v0.12,'
' please use --output-format=json instead)', ('-j', '--json'))
)
def _optional_output(self, r):
if self['json_output']:
print_json(r, out=self)
elif self['with_output']:
print_items([r] if isinstance(r, dict) else r, out=self)
class _optional_json(object):
oj_arguments = dict(
output_format=OutputFormatArgument(
'Show output in chosen output format (%s)' % ', '.join(
OutputFormatArgument.formats),
'--output-format'),
json_output=FlagArgument(
'show output in json (DEPRECATED from v0.12,'
' please use --output-format instead)', ('-j', '--json'))
)
def _print(self, output, print_method=print_items, **print_method_kwargs):
if self['json_output'] or self['output_format']:
print_json(output, out=self)
if self['output_format']:
func = OutputFormatArgument.formats[self['output_format']]
func(output, out=self)
else:
print_method_kwargs.setdefault('out', self)
print_method(output, **print_method_kwargs)
......
......@@ -37,7 +37,7 @@ from os.path import abspath
from kamaki.cli import command
from kamaki.clients.astakos import LoggedAstakosClient
from kamaki.cli.cmds import (
CommandInit, errors, _optional_json, addLogSettings, _name_filter)
CommandInit, errors, OptionalOutput, addLogSettings, _name_filter)
from kamaki.cli.cmdtree import CommandTree
from kamaki.cli.errors import (
CLIBaseUrlError, CLISyntaxError, CLIError, CLIInvalidArgument)
......@@ -116,7 +116,7 @@ class _init_synnefo_astakosclient(CommandInit):
@command(user_commands)
class user_authenticate(_init_synnefo_astakosclient, _optional_json):
class user_authenticate(_init_synnefo_astakosclient, OptionalOutput):
"""Authenticate a user and get all authentication information"""
@errors.generic.all
......@@ -132,7 +132,7 @@ class user_authenticate(_init_synnefo_astakosclient, _optional_json):
@command(user_commands)
class user_uuid2name(_init_synnefo_astakosclient, _optional_json):
class user_uuid2name(_init_synnefo_astakosclient, OptionalOutput):
"""Get user name(s) from uuid(s)"""
#@errors.generic.all
......@@ -150,7 +150,7 @@ class user_uuid2name(_init_synnefo_astakosclient, _optional_json):
@command(user_commands)
class user_name2uuid(_init_synnefo_astakosclient, _optional_json):
class user_name2uuid(_init_synnefo_astakosclient, OptionalOutput):
"""Get user uuid(s) from name(s)"""
@errors.generic.all
......@@ -168,7 +168,7 @@ class user_name2uuid(_init_synnefo_astakosclient, _optional_json):
@command(quota_commands)
class quota_list(_init_synnefo_astakosclient, _optional_json):
class quota_list(_init_synnefo_astakosclient, OptionalOutput):
"""Show user quotas"""
_to_format = set(['cyclades.disk', 'pithos.diskspace', 'cyclades.ram'])
......@@ -221,7 +221,7 @@ class quota_list(_init_synnefo_astakosclient, _optional_json):
@command(user_commands)
class user_info(_init_synnefo_astakosclient, _optional_json):
class user_info(_init_synnefo_astakosclient, OptionalOutput):
"""Get info for (current) session user"""
arguments = dict(
......@@ -253,7 +253,7 @@ class user_info(_init_synnefo_astakosclient, _optional_json):
@command(user_commands)
class user_add(_init_synnefo_astakosclient, _optional_json):
class user_add(_init_synnefo_astakosclient, OptionalOutput):
"""Authenticate a user by token and add to kamaki session (cache)"""
@errors.generic.all
......@@ -277,7 +277,7 @@ class user_add(_init_synnefo_astakosclient, _optional_json):
@command(user_commands)
class user_list(_init_synnefo_astakosclient, _optional_json):
class user_list(_init_synnefo_astakosclient, OptionalOutput):
"""List (cached) session users"""
arguments = dict(
......@@ -373,7 +373,7 @@ class user_delete(_init_synnefo_astakosclient):
# command admin
@command(service_commands)
class service_list(_init_synnefo_astakosclient, _optional_json):
class service_list(_init_synnefo_astakosclient, OptionalOutput):
"""List available services"""
@errors.generic.all
......@@ -387,7 +387,7 @@ class service_list(_init_synnefo_astakosclient, _optional_json):
@command(service_commands)
class service_uuid2username(_init_synnefo_astakosclient, _optional_json):
class service_uuid2username(_init_synnefo_astakosclient, OptionalOutput):
"""Get service username(s) from uuid(s)"""
@errors.generic.all
......@@ -407,7 +407,7 @@ class service_uuid2username(_init_synnefo_astakosclient, _optional_json):
@command(service_commands)
class service_username2uuid(_init_synnefo_astakosclient, _optional_json):
class service_username2uuid(_init_synnefo_astakosclient, OptionalOutput):
"""Get service uuid(s) from username(s)"""
@errors.generic.all
......@@ -427,7 +427,7 @@ class service_username2uuid(_init_synnefo_astakosclient, _optional_json):
@command(service_commands)
class service_quotas(_init_synnefo_astakosclient, _optional_json):
class service_quotas(_init_synnefo_astakosclient, OptionalOutput):
"""Get service quotas"""
arguments = dict(
......@@ -446,7 +446,7 @@ class service_quotas(_init_synnefo_astakosclient, _optional_json):
@command(commission_commands)
class commission_pending(_init_synnefo_astakosclient, _optional_json):
class commission_pending(_init_synnefo_astakosclient, OptionalOutput):
"""List pending commissions (special privileges required)"""
@errors.generic.all
......@@ -460,7 +460,7 @@ class commission_pending(_init_synnefo_astakosclient, _optional_json):
@command(commission_commands)
class commission_info(_init_synnefo_astakosclient, _optional_json):
class commission_info(_init_synnefo_astakosclient, OptionalOutput):
"""Get commission info (special privileges required)"""
@errors.generic.all
......@@ -506,7 +506,7 @@ class commission_reject(_init_synnefo_astakosclient):
@command(commission_commands)
class commission_resolve(_init_synnefo_astakosclient, _optional_json):
class commission_resolve(_init_synnefo_astakosclient, OptionalOutput):
"""Resolve multiple commissions (special privileges required)"""
arguments = dict(
......@@ -533,7 +533,7 @@ class commission_resolve(_init_synnefo_astakosclient, _optional_json):
@command(commission_commands)
class commission_issue(_init_synnefo_astakosclient, _optional_json):
class commission_issue(_init_synnefo_astakosclient, OptionalOutput):
"""Issue commissions as a json string (special privileges required)
Parameters:
holder -- user's id (string)
......@@ -561,7 +561,7 @@ class commission_issue(_init_synnefo_astakosclient, _optional_json):
@command(resource_commands)
class resource_list(_init_synnefo_astakosclient, _optional_json):
class resource_list(_init_synnefo_astakosclient, OptionalOutput):
"""List user resources"""
@errors.generic.all
......@@ -576,7 +576,7 @@ class resource_list(_init_synnefo_astakosclient, _optional_json):
@command(endpoint_commands)
class endpoint_list(
_init_synnefo_astakosclient, _optional_json, _name_filter):
_init_synnefo_astakosclient, OptionalOutput, _name_filter):
"""Get endpoints service endpoints"""
arguments = dict(endpoint_type=ValueArgument('Filter by type', '--type'))
......@@ -625,7 +625,7 @@ def apply_notification(func):
@command(project_commands)
class project_list(_init_synnefo_astakosclient, _optional_json):
class project_list(_init_synnefo_astakosclient, OptionalOutput):
"""List all projects"""
arguments = dict(
......@@ -653,7 +653,7 @@ class project_list(_init_synnefo_astakosclient, _optional_json):
@command(project_commands)
class project_info(_init_synnefo_astakosclient, _optional_json):
class project_info(_init_synnefo_astakosclient, OptionalOutput):
"""Get details for a project"""
@errors.generic.all
......@@ -721,7 +721,7 @@ class ProjectResourceArgument(KeyValueArgument):
@command(project_commands)
class project_create(_init_synnefo_astakosclient, _optional_json):
class project_create(_init_synnefo_astakosclient, OptionalOutput):
"""Apply for a new project"""
__doc__ += _project_specs
......@@ -790,7 +790,7 @@ class project_create(_init_synnefo_astakosclient, _optional_json):
@command(project_commands)
class project_modify(_init_synnefo_astakosclient, _optional_json):
class project_modify(_init_synnefo_astakosclient, OptionalOutput):
"""Modify properties of a project"""
__doc__ += _project_specs
......@@ -956,7 +956,7 @@ class membership(_init_synnefo_astakosclient):
@command(membership_commands)
class membership_list(_init_synnefo_astakosclient, _optional_json):
class membership_list(_init_synnefo_astakosclient, OptionalOutput):
"""List all memberships"""
arguments = dict(
......@@ -974,7 +974,7 @@ class membership_list(_init_synnefo_astakosclient, _optional_json):
@command(membership_commands)
class membership_info(_init_synnefo_astakosclient, _optional_json):
class membership_info(_init_synnefo_astakosclient, OptionalOutput):
"""Details on a membership"""
@errors.generic.all
......@@ -988,7 +988,7 @@ class membership_info(_init_synnefo_astakosclient, _optional_json):
self._run(memb_id=membership_id)
class _membership_action(_init_synnefo_astakosclient, _optional_json):
class _membership_action(_init_synnefo_astakosclient, OptionalOutput):
action = ''
arguments = dict(reason=ValueArgument('Reason for the action', '--reason'))
......
......@@ -47,8 +47,8 @@ from kamaki.cli.argument import (
FlagArgument, ValueArgument, KeyValueArgument, RepeatableArgument,
ProgressBarArgument, DateArgument, IntArgument, StatusArgument)
from kamaki.cli.cmds import (
CommandInit, errors, addLogSettings, dataModification,
_optional_output_cmd, _optional_json, _name_filter, _id_filter)
CommandInit, errors, addLogSettings, dataModification, OptionalOutput,
_name_filter, _id_filter)
server_cmds = CommandTree('server', 'Cyclades/Compute API server commands')
......@@ -152,7 +152,7 @@ class _init_cyclades(CommandInit):
@command(server_cmds)
class server_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
class server_list(_init_cyclades, OptionalOutput, _name_filter, _id_filter):
"""List virtual servers accessible by user
Use filtering arguments (e.g., --name-like) to manage long server lists
"""
......@@ -274,7 +274,7 @@ class server_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
@command(server_cmds)
class server_info(_init_cyclades, _optional_json):
class server_info(_init_cyclades, OptionalOutput):
"""Detailed information on a Virtual Machine"""
arguments = dict(
......@@ -424,7 +424,7 @@ class NetworkArgument(RepeatableArgument):
@command(server_cmds)
class server_create(_init_cyclades, _optional_json, _server_wait):
class server_create(_init_cyclades, OptionalOutput, _server_wait):
"""Create a server (aka Virtual Machine)"""
arguments = dict(
......@@ -545,7 +545,7 @@ class FirewallProfileArgument(ValueArgument):
@command(server_cmds)
class server_modify(_init_cyclades, _optional_output_cmd):
class server_modify(_init_cyclades):
"""Modify attributes of a virtual server"""
arguments = dict(
......@@ -624,8 +624,6 @@ class server_modify(_init_cyclades, _optional_output_cmd):
for key in (self['metadata_to_delete'] or []):
errors.cyclades.metadata(
self.client.delete_server_metadata)(server_id, key=key)
if self['with_output']:
self._optional_output(self.client.get_server_details(server_id))
def main(self, server_id):
super(self.__class__, self)._run()
......@@ -639,7 +637,7 @@ class server_modify(_init_cyclades, _optional_output_cmd):
@command(server_cmds)
class server_reassign(_init_cyclades, _optional_json):
class server_reassign(_init_cyclades, OptionalOutput):
"""Assign a virtual server to a different project"""
arguments = dict(
......@@ -659,7 +657,7 @@ class server_reassign(_init_cyclades, _optional_json):
@command(server_cmds)
class server_delete(_init_cyclades, _optional_output_cmd, _server_wait):
class server_delete(_init_cyclades, _server_wait):
"""Delete a virtual server"""
arguments = dict(
......@@ -689,9 +687,7 @@ class server_delete(_init_cyclades, _optional_output_cmd, _server_wait):
details = self.client.get_server_details(server_id)
status = details['status']
r = self.client.delete_server(server_id)
self._optional_output(r)
self.client.delete_server(server_id)
if self['wait']:
self._wait(server_id, status)
......@@ -701,7 +697,7 @@ class server_delete(_init_cyclades, _optional_output_cmd, _server_wait):
@command(server_cmds)
class server_reboot(_init_cyclades, _optional_output_cmd, _server_wait):
class server_reboot(_init_cyclades, _server_wait):
"""Reboot a virtual server"""
arguments = dict(
......@@ -731,9 +727,7 @@ class server_reboot(_init_cyclades, _optional_output_cmd, _server_wait):
importance=2, details=[
'--type values are either SOFT (default) or HARD'])
r = self.client.reboot_server(int(server_id), hard_reboot)
self._optional_output(r)
self.client.reboot_server(int(server_id), hard_reboot)
if self['wait']:
self._wait(server_id, 'REBOOT')
......@@ -743,7 +737,7 @@ class server_reboot(_init_cyclades, _optional_output_cmd, _server_wait):
@command(server_cmds)
class server_start(_init_cyclades, _optional_output_cmd, _server_wait):
class server_start(_init_cyclades, _server_wait):
"""Start an existing virtual server"""
arguments = dict(
......@@ -761,9 +755,7 @@ class server_start(_init_cyclades, _optional_output_cmd, _server_wait):
if status in ('ACTIVE', ):
return
r = self.client.start_server(int(server_id))
self._optional_output(r)
self.client.start_server(int(server_id))
if self['wait']:
self._wait(server_id, status)
......@@ -773,7 +765,7 @@ class server_start(_init_cyclades, _optional_output_cmd, _server_wait):
@command(server_cmds)
class server_shutdown(_init_cyclades, _optional_output_cmd, _server_wait):
class server_shutdown(_init_cyclades, _server_wait):
"""Shutdown an active virtual server"""
arguments = dict(
......@@ -791,9 +783,7 @@ class server_shutdown(_init_cyclades, _optional_output_cmd, _server_wait):
if status in ('STOPPED', ):
return
r = self.client.shutdown_server(int(server_id))
self._optional_output(r)
self.client.shutdown_server(int(server_id))
if self['wait']:
self._wait(server_id, status)
......@@ -803,7 +793,7 @@ class server_shutdown(_init_cyclades, _optional_output_cmd, _server_wait):
@command(server_cmds)
class server_console(_init_cyclades, _optional_json):
class server_console(_init_cyclades, OptionalOutput):
"""Create a VMC console and show connection information"""
@errors.generic.all
......@@ -854,7 +844,7 @@ class server_wait(_init_cyclades, _server_wait):
@command(flavor_cmds)
class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
class flavor_list(_init_cyclades, OptionalOutput, _name_filter, _id_filter):
"""List available hardware flavors"""
PERMANENTS = ('id', 'name')
......@@ -896,8 +886,7 @@ class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
flavors = self._filter_by_id(flavors)
if withcommons:
flavors = self._apply_common_filters(flavors)
if not (self['detail'] or (
self['json_output'] or self['output_format'])):
if not (self['detail'] or self['output_format']):
remove_from_items(flavors, 'links')
if detail and not self['detail']:
for flv in flavors:
......@@ -917,7 +906,7 @@ class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
@command(flavor_cmds)
class flavor_info(_init_cyclades, _optional_json):
class flavor_info(_init_cyclades, OptionalOutput):
"""Detailed information on a hardware flavor
To get a list of available flavors and flavor ids, try /flavor list
"""
......
......@@ -49,8 +49,8 @@ from kamaki.cli.argument import (
from kamaki.cli.cmds.cyclades import _init_cyclades
from kamaki.cli.errors import CLIError, raiseCLIError, CLIInvalidArgument
from kamaki.cli.cmds import (
CommandInit, errors, addLogSettings, _optional_output_cmd, _optional_json,
_name_filter, _id_filter)
CommandInit, errors, addLogSettings, OptionalOutput, _name_filter,
_id_filter)
image_cmds = CommandTree('image', 'Cyclades/Plankton API image commands')
......@@ -158,7 +158,7 @@ def _validate_image_location(location):
@command(image_cmds)
class image_list(_init_image, _optional_json, _name_filter, _id_filter):
class image_list(_init_image, OptionalOutput, _name_filter, _id_filter):
"""List images accessible by user"""
PERMANENTS = (
......@@ -219,7 +219,7 @@ class image_list(_init_image, _optional_json, _name_filter, _id_filter):
def _members(self, image_id):
members = self.client.list_members(image_id)
if not (self['json_output'] or self['output_format']):
if not self['output_format']:
uuids = [member['member_id'] for member in members]
usernames = self._uuids2usernames(uuids)
for member in members:
......@@ -256,8 +256,7 @@ class image_list(_init_image, _optional_json, _name_filter, _id_filter):
images = self._filter_by_id(images)
images = self._non_exact_name_filter(images)
if self['detail'] and not (
self['json_output'] or self['output_format']):
if self['detail'] and not self['output_format']:
images = self._add_owner_name(images)
elif detail and not self['detail']:
for img in images:
......@@ -279,7 +278,7 @@ class image_list(_init_image, _optional_json, _name_filter, _id_filter):
@command(image_cmds)
class image_info(_init_image, _optional_json):
class image_info(_init_image, OptionalOutput):
"""Get image metadata"""
@errors.generic.all
......@@ -287,7 +286,7 @@ class image_info(_init_image, _optional_json):
@errors.plankton.id
def _run(self, image_id):
meta = self.client.get_meta(image_id)
if not (self['json_output'] or self['output_format']):
if not self['output_format']:
meta['owner'] += ' (%s)' % self._uuid2username(meta['owner'])
self._print(meta, self.print_dict)
......@@ -297,7 +296,7 @@ class image_info(_init_image, _optional_json):
@command(image_cmds)
class image_modify(_init_image, _optional_output_cmd):
class image_modify(_init_image):
"""Add / update metadata and properties for an image
The original image preserves the values that are not affected
"""
......@@ -338,16 +337,14 @@ class image_modify(_init_image, _optional_output_cmd):
meta['properties'][k.upper()] = v
for k in (self['property_to_del'] or []):
meta['properties'][k.upper()] = None
self._optional_output(self.client.update_image(
self.client.update_image(
image_id,
name=self['image_name'],
disk_format=self['disk_format'],
container_format=self['container_format'],
status=self['status'],
public=self['publish'] or (False if self['unpublish'] else None),
**meta['properties']))
if self['with_output']:
self._optional_output(self.get_image_details(image_id))
**meta['properties'])
def main(self, image_id):
super(self.__class__, self)._run()
......@@ -401,7 +398,7 @@ class PithosLocationArgument(ValueArgument):
@command(image_cmds)
class image_register(_init_image, _optional_json):
class image_register(_init_image, OptionalOutput):
"""(Re)Register an image file to an Image service
The image file must be stored at a pithos repository
Some metadata can be set by user (e.g., disk-format) while others are set
......@@ -570,7 +567,7 @@ class image_register(_init_image, _optional_json):
'Failed to dump metafile /%s/%s' % (
locator.container, meta_path))
return
if self['json_output'] or self['output_format']:
if self['output_format']:
self.print_json(dict(
metafile_location='/%s/%s' % (
locator.container, meta_path),
......@@ -607,14 +604,14 @@ class image_register(_init_image, _optional_json):
@command(image_cmds)
class image_unregister(_init_image, _optional_output_cmd):
class image_unregister(_init_image):
"""Unregister an image (does not delete the image file)"""
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id):
self._optional_output(self.client.unregister(image_id))
self.client.unregister(image_id)
def main(self, image_id):
super(self.__class__, self)._run()
......@@ -625,7 +622,7 @@ class image_unregister(_init_image, _optional_output_cmd):
@command(imagecompute_cmds)
class imagecompute_list(
_init_cyclades, _optional_json, _name_filter, _id_filter):
_init_cyclades, OptionalOutput, _name_filter, _id_filter):
"""List images"""
PERMANENTS = ('id', 'name')
......@@ -681,8 +678,7 @@ class imagecompute_list(
images = self._filter_by_user(images)
if withmeta:
images = self._filter_by_metadata(images)
if self['detail'] and not (
self['json_output'] or self['output_format']):
if self['detail'] and not self['output_format']:
images = self._add_name(self._add_name(images, 'tenant_id'))
elif detail and not self['detail']:
for img in images:
......@@ -704,7 +700,7 @@ class imagecompute_list(
@command(imagecompute_cmds)
class imagecompute_info(_init_cyclades, _optional_json):
class imagecompute_info(_init_cyclades, OptionalOutput):
"""Get detailed information on an image"""
@errors.generic.all
......@@ -723,14 +719,14 @@ class imagecompute_info(_init_cyclades, _optional_json):
@command(imagecompute_cmds)
class imagecompute_delete(_init_cyclades, _optional_output_cmd):
class imagecompute_delete(_init_cyclades):
"""Delete an image (WARNING: image file is also removed)"""
@errors.generic.all
@errors.cyclades.connection
@errors.plankton.id
def _run(self, image_id):
self._optional_output(self.client.delete_image(image_id))
self.client.delete_image(image_id)
def main(self, image_id):
super(self.__class__, self)._run()
......@@ -738,7 +734,7 @@ class imagecompute_delete(_init_cyclades, _optional_output_cmd):
@command(imagecompute_cmds)
class imagecompute_modify(_init_cyclades, _optional_output_cmd):
class imagecompute_modify(_init_cyclades):
"""Modify image properties (metadata)"""
arguments = dict(
......@@ -760,8 +756,6 @@ class imagecompute_modify(_init_cyclades, _optional_output_cmd):
image_id, **self['property_to_add'])
for key in (self['property_to_del'] or []):
self.client.delete_image_metadata(image_id, key)
if self['with_output']:
self._optional_output(self.client.get_image_details(image_id))
def main(self, image_id):
super(self.__class__, self)._run()
......
......@@ -44,8 +44,8 @@ from kamaki.cli.argument import (
FlagArgument, ValueArgument, RepeatableArgument, IntArgument,
StatusArgument)
from kamaki.cli.cmds import (
CommandInit, errors, addLogSettings, _optional_output_cmd,
_optional_json, _name_filter, _id_filter)
CommandInit, errors, addLogSettings, OptionalOutput, _name_filter,
_id_filter)
from kamaki.cli.cmds.cyclades import _service_wait