- Restore 2nd level command syntax in shell [#3736]
- Allow copy of deleted objects by refering to older version [#3737]
- Add image.add_member missing content-length header
+- Unquote http respons headers
Changes:
-image compute:
delete, properties delete
- server: rename, delete, reboot, start, shutdown, firewall-set
-
+ - network: rename, delete, connect
+- Add optional json for methods with output [#3732]
+ - file:
+ list, hashmap, permissions-get, info, metadata-get, quota,
+ containerlimit-get, group-list, sharers, versions
+ - server: list, info, create, console, addr, metadata-list/set, stats
+ - image: list, meta, register, shared, list
+ - image compute: list, info, properties-list/get/add/set
+ - flavor: list, info
+ - network: info, list, create
+ - astakos: authenticate
- Transliterate methods to list-get-set-delete command groups:
- file: permissions, versioning, group and metadata
- image: members, member
- image compute: properties
- server: firewall, metadata
-
Features:
- A logger module container a set of basic loging method for kamaki [#3668]
download : Download a file or directory
group : Manage access groups and group members
delete: Delete a user group
- get : Get groups and group members
+ list : List groups and group members
set : Set a user group
hashmap : Get the hashmap of an object
info : Get information for account [, container [or object]]
* download Download a file or directory
* group Manage access groups and group members
* delete Delete a user group
- * get Get groups and group members
+ * list List groups and group members
* set Set a user group
* hashmap Get the hashmap of an object
* info Get information for account [, container [or object]]
arguments.update(self.arguments)
if isinstance(self, _optional_output_cmd):
arguments.update(self.oo_arguments)
+ if isinstance(self, _optional_json):
+ arguments.update(self.oj_arguments)
self.arguments = dict(arguments)
try:
self.config = self['config']
return self[argterm]
+# feature classes - inherit them to get special features for your commands
+
+
class _optional_output_cmd(object):
oo_arguments = dict(
print_json(r)
elif self['with_output']:
print_items([r] if isinstance(r, dict) else r)
+
+
+class _optional_json(object):
+
+ oj_arguments = dict(
+ json_output=FlagArgument('show headers in json', ('-j', '--json'))
+ )
+
+ def _print(self, output, print_method=print_items, **print_method_kwargs):
+ if self['json_output']:
+ print_json(output)
+ else:
+ print_method(output, **print_method_kwargs)
from kamaki.cli import command
from kamaki.clients.astakos import AstakosClient
-from kamaki.cli.utils import print_dict, print_json
-from kamaki.cli.commands import _command_init, errors
+from kamaki.cli.commands import _command_init, errors, _optional_json
from kamaki.cli.command_tree import CommandTree
-from kamaki.cli.argument import FlagArgument
user_cmds = CommandTree('user', 'Astakos API commands')
_commands = [user_cmds]
@command(user_cmds)
-class user_authenticate(_user_init):
+class user_authenticate(_user_init, _optional_json):
"""Authenticate a user
Get user information (e.g. unique account name) from token
Token should be set in settings:
Token can also be provided as a parameter
"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.user.authenticate
def _run(self, custom_token=None):
super(self.__class__, self)._run()
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.authenticate(custom_token))
+ self._print(
+ [self.client.authenticate(custom_token)],
+ title=('uuid', 'name',), with_redundancy=True)
def main(self, custom_token=None):
self._run(custom_token)
from kamaki.clients.cyclades import CycladesClient, ClientError
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
from kamaki.cli.argument import ProgressBarArgument, DateArgument, IntArgument
-from kamaki.cli.commands import _command_init, errors, _optional_output_cmd
+from kamaki.cli.commands import _command_init, errors
+from kamaki.cli.commands import _optional_output_cmd, _optional_json
from base64 import b64encode
from os.path import exists
@command(server_cmds)
-class server_list(_init_cyclades):
+class server_list(_init_cyclades, _optional_json):
"""List Virtual Machines accessible by user"""
__doc__ += about_authentication
more=FlagArgument(
'output results in pages (-n to set items per page, default 10)',
'--more'),
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
def _make_results_pretty(self, servers):
@errors.cyclades.date
def _run(self):
servers = self.client.list_servers(self['detail'], self['since'])
- if self['json_output']:
- print_json(servers)
- return
- if self['detail']:
+
+ if self['detail'] and not self['json_output']:
self._make_results_pretty(servers)
+ kwargs = dict(with_enumeration=self['enum'])
if self['more']:
- print_items(
- servers,
- page_size=self['limit'] if self['limit'] else 10,
- with_enumeration=self['enum'])
- else:
- print_items(
- servers[:self['limit'] if self['limit'] else len(servers)],
- with_enumeration=self['enum'])
+ kwargs['page_size'] = self['limit'] if self['limit'] else 10
+ elif self['limit']:
+ servers = servers[:self['limit']]
+ self._print(servers, **kwargs)
def main(self):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_info(_init_cyclades):
+class server_info(_init_cyclades, _optional_json):
"""Detailed information on a Virtual Machine
Contains:
- name, id, status, create/update dates
- hardware flavor and os image ids
"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
- def _print(self, server):
+ def _pretty(self, server):
addr_dict = {}
if 'attachments' in server:
atts = server.pop('attachments')
@errors.cyclades.connection
@errors.cyclades.server_id
def _run(self, server_id):
- printer = print_json if self['json_output'] else self._print
- printer(self.client.get_server_details(server_id))
+ self._print(self.client.get_server_details(server_id), self._pretty)
def main(self, server_id):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_create(_init_cyclades):
+class server_create(_init_cyclades, _optional_json):
"""Create a server (aka Virtual Machine)
Parameters:
- name: (single quoted text)
arguments = dict(
personality=PersonalityArgument(
- (80 * ' ').join(howto_personality),
- ('-p', '--personality')),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ (80 * ' ').join(howto_personality), ('-p', '--personality'))
)
@errors.generic.all
@errors.plankton.id
@errors.cyclades.flavor_id
def _run(self, name, flavor_id, image_id):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.create_server(
- name,
- int(flavor_id),
- image_id,
- self['personality']))
+ self._print([self.client.create_server(
+ name, int(flavor_id), image_id, self['personality'])])
def main(self, name, flavor_id, image_id):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_console(_init_cyclades):
+class server_console(_init_cyclades, _optional_json):
"""Get a VNC console to access an existing server (VM)
Console connection information provided (at least):
- host: (url or address) a VNC host
- password: for VNC authorization
"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.cyclades.server_id
def _run(self, server_id):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_server_console(int(server_id)))
+ self._print([self.client.get_server_console(int(server_id))])
def main(self, server_id):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_addr(_init_cyclades):
+class server_addr(_init_cyclades, _optional_json):
"""List the addresses of all network interfaces on a server (VM)"""
arguments = dict(
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
@errors.generic.all
@errors.cyclades.server_id
def _run(self, server_id):
reply = self.client.list_server_nics(int(server_id))
- if self['json_output']:
- print_json(reply)
- else:
- print_items(
- reply,
- with_enumeration=self['enum'] and len(reply) > 1)
+ self._print(
+ reply, with_enumeration=self['enum'] and len(reply) > 1)
def main(self, server_id):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_metadata_list(_init_cyclades):
+class server_metadata_list(_init_cyclades, _optional_json):
"""Get server metadata"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.cyclades.server_id
@errors.cyclades.metadata
def _run(self, server_id, key=''):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_server_metadata(int(server_id), key))
+ self._print(
+ [self.client.get_server_metadata(int(server_id), key)], title=())
def main(self, server_id, key=''):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_metadata_set(_init_cyclades):
+class server_metadata_set(_init_cyclades, _optional_json):
"""Set / update server(VM) metadata
Metadata should be given in key/value pairs in key=value format
For example:
Old, unreferenced metadata will remain intact
"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.cyclades.server_id
def _run(self, server_id, keyvals):
+ assert keyvals, 'Please, add some metadata ( key=value)'
metadata = dict()
- print('TO ANALYZE:', keyvals)
for keyval in keyvals:
k, sep, v = keyval.partition('=')
if sep and k:
'For example:',
'/server metadata set <server id>'
'key1=value1 key2=value2'])
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.update_server_metadata(int(server_id), **metadata))
+ self._print(
+ [self.client.update_server_metadata(int(server_id), **metadata)],
+ title=())
def main(self, server_id, *key_equals_val):
super(self.__class__, self)._run()
@command(server_cmds)
-class server_stats(_init_cyclades):
+class server_stats(_init_cyclades, _optional_json):
"""Get server (VM) statistics"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.cyclades.server_id
def _run(self, server_id):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_server_stats(int(server_id)))
+ self._print([self.client.get_server_stats(int(server_id))])
def main(self, server_id):
super(self.__class__, self)._run()
@command(flavor_cmds)
-class flavor_list(_init_cyclades):
+class flavor_list(_init_cyclades, _optional_json):
"""List available hardware flavors"""
arguments = dict(
more=FlagArgument(
'output results in pages (-n to set items per page, default 10)',
'--more'),
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
@errors.generic.all
@errors.cyclades.connection
def _run(self):
flavors = self.client.list_flavors(self['detail'])
- if self['json_output']:
- print_json(flavors)
- return
pg_size = 10 if self['more'] and not self['limit'] else self['limit']
- print_items(
+ self._print(
flavors,
with_redundancy=self['detail'],
page_size=pg_size,
@command(flavor_cmds)
-class flavor_info(_init_cyclades):
+class flavor_info(_init_cyclades, _optional_json):
"""Detailed information on a hardware flavor
To get a list of available flavors and flavor ids, try /flavor list
"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.cyclades.flavor_id
def _run(self, flavor_id):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_flavor_details(int(flavor_id)))
+ self._print([self.client.get_flavor_details(int(flavor_id))])
def main(self, flavor_id):
super(self.__class__, self)._run()
@command(network_cmds)
-class network_info(_init_cyclades):
+class network_info(_init_cyclades, _optional_json):
"""Detailed information on a network
To get a list of available networks and network ids, try /network list
"""
- arguments = dict(
- json_output=FlagArgument('show output in json', ('-j', '--json'))
- )
-
@classmethod
def _make_result_pretty(self, net):
if 'attachments' in net:
@errors.cyclades.network_id
def _run(self, network_id):
network = self.client.get_network_details(int(network_id))
- if self['json_output']:
- print_json(network)
- return
self._make_result_pretty(network)
- print_dict(network, exclude=('id'))
+ #print_dict(network, exclude=('id'))
+ self._print(network, print_dict, exclude=('id'))
def main(self, network_id):
super(self.__class__, self)._run()
@command(network_cmds)
-class network_list(_init_cyclades):
+class network_list(_init_cyclades, _optional_json):
"""List networks"""
arguments = dict(
more=FlagArgument(
'output results in pages (-n to set items per page, default 10)',
'--more'),
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
def _make_results_pretty(self, nets):
@errors.cyclades.connection
def _run(self):
networks = self.client.list_networks(self['detail'])
- if self['json_output']:
- print_json(networks)
- return
if self['detail']:
self._make_results_pretty(networks)
+ kwargs = dict(with_enumeration=self['enum'])
if self['more']:
- print_items(
- networks,
- page_size=self['limit'] or 10, with_enumeration=self['enum'])
+ kwargs['page_size'] = self['limit'] or 10
elif self['limit']:
- print_items(
- networks[:self['limit']],
- with_enumeration=self['enum'])
- else:
- print_items(networks, with_enumeration=self['enum'])
+ networks = networks[:self['limit']]
+ self._print(networks, **kwargs)
def main(self):
super(self.__class__, self)._run()
@command(network_cmds)
-class network_create(_init_cyclades):
+class network_create(_init_cyclades, _optional_json):
"""Create an (unconnected) network"""
arguments = dict(
'Valid network types are '
'CUSTOM, IP_LESS_ROUTED, MAC_FILTERED (default), PHYSICAL_VLAN',
'--with-type',
- default='MAC_FILTERED'),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ default='MAC_FILTERED')
)
@errors.generic.all
@errors.cyclades.connection
@errors.cyclades.network_max
def _run(self, name):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.create_network(
+ self._print([self.client.create_network(
name,
cidr=self['cidr'],
gateway=self['gateway'],
dhcp=self['dhcp'],
- type=self['type']))
+ type=self['type'])])
def main(self, name):
super(self.__class__, self)._run()
from kamaki.cli.argument import FlagArgument, ValueArgument, KeyValueArgument
from kamaki.cli.argument import IntArgument
from kamaki.cli.commands.cyclades import _init_cyclades
-from kamaki.cli.commands import _command_init, errors, _optional_output_cmd
+from kamaki.cli.commands import _command_init, errors
+from kamaki.cli.commands import _optional_output_cmd, _optional_json
image_cmds = CommandTree(
@command(image_cmds)
-class image_list(_init_image):
+class image_list(_init_image, _optional_json):
"""List images accessible by user"""
arguments = dict(
more=FlagArgument(
'output results in pages (-n to set items per page, default 10)',
'--more'),
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
def _filtered_by_owner(self, detail, *list_params):
else:
images = self.client.list_public(detail, filters, order)
- if self['json_output']:
- print_json(images)
- return
images = self._filtered_by_name(images)
+ kwargs = dict(with_enumeration=self['enum'])
if self['more']:
- print_items(
- images,
- with_enumeration=self['enum'], page_size=self['limit'] or 10)
+ kwargs['page_size'] = self['limit'] or 10
elif self['limit']:
- print_items(images[:self['limit']], with_enumeration=self['enum'])
- else:
- print_items(images, with_enumeration=self['enum'])
+ images = images[:self['limit']]
+ self._print(images, **kwargs)
def main(self):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_meta(_init_image):
+class image_meta(_init_image, _optional_json):
"""Get image metadata
Image metadata include:
- image file information (location, size, etc.)
- image os properties (os, fs, etc.)
"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_meta(image_id))
+ self._print([self.client.get_meta(image_id)])
def main(self, image_id):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_register(_init_image):
+class image_register(_init_image, _optional_json):
"""(Re)Register an image"""
arguments = dict(
'add property in key=value form (can be repeated)',
('-p', '--property')),
is_public=FlagArgument('mark image as public', '--public'),
- size=IntArgument('set image size', '--size'),
- #update=FlagArgument(
- # 'update existing image properties',
- # ('-u', '--update')),
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
+ size=IntArgument('set image size', '--size')
)
@errors.generic.all
'size',
'is_public']).intersection(self.arguments):
params[key] = self[key]
+ properties = self['properties']
- properties = self['properties']
-
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.register(name, location, params, properties))
+ self._print([self.client.register(name, location, params, properties)])
def main(self, name, location):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_shared(_init_image):
+class image_shared(_init_image, _optional_json):
"""List images shared by a member"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.plankton.connection
def _run(self, member):
- r = self.client.list_shared(member)
- if self['json_output']:
- print_json(r)
- else:
- print_items(r, title=('image_id',))
+ self._print(self.client.list_shared(member), title=('image_id',))
def main(self, member):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_members_list(_init_image):
+class image_members_list(_init_image, _optional_json):
"""List members of an image"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.plankton.connection
@errors.plankton.id
def _run(self, image_id):
- members = self.client.list_members(image_id)
- if self['json_output']:
- print_json(members)
- else:
- print_items(members, title=('member_id',), with_redundancy=True)
+ self._print(self.client.list_members(image_id), title=('member_id',))
def main(self, image_id):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_compute_list(_init_cyclades):
+class image_compute_list(_init_cyclades, _optional_json):
"""List images"""
arguments = dict(
more=FlagArgument(
'output results in pages (-n to set items per page, default 10)',
'--more'),
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
def _make_results_pretty(self, images):
@errors.cyclades.connection
def _run(self):
images = self.client.list_images(self['detail'])
- if self['json_output']:
- print_json(images)
- return
- if self['detail']:
+ if self['detail'] and not self['json_output']:
self._make_results_pretty(images)
+ kwargs = dict(with_enumeration=self['enum'])
if self['more']:
- print_items(
- images,
- page_size=self['limit'] or 10, with_enumeration=self['enum'])
+ kwargs['page_size'] = self['limit'] or 10
else:
- print_items(images[:self['limit']], with_enumeration=self['enum'])
+ images = images[:self['limit']]
+ self._print(images, **kwargs)
def main(self):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_compute_info(_init_cyclades):
+class image_compute_info(_init_cyclades, _optional_json):
"""Get detailed information on an image"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.plankton.id
def _run(self, image_id):
image = self.client.get_image_details(image_id)
- if self['json_output']:
- print_json(image)
- return
- if 'metadata' in image:
+ if (not self['json_output']) and 'metadata' in image:
image['metadata'] = image['metadata']['values']
- print_dict(image)
+ self._print([image])
def main(self, image_id):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_compute_properties_list(_init_cyclades):
+class image_compute_properties_list(_init_cyclades, _optional_json):
"""List all image properties"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.plankton.id
def _run(self, image_id):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_image_metadata(image_id))
+ self._print(self.client.get_image_metadata(image_id), print_dict)
def main(self, image_id):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_compute_properties_get(_init_cyclades):
+class image_compute_properties_get(_init_cyclades, _optional_json):
"""Get an image property"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.plankton.id
@errors.plankton.metadata
def _run(self, image_id, key):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.get_image_metadata(image_id, key))
+ self._print(self.client.get_image_metadata(image_id, key), print_dict)
def main(self, image_id, key):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_compute_properties_add(_init_cyclades):
+class image_compute_properties_add(_init_cyclades, _optional_json):
"""Add a property to an image"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
-
@errors.generic.all
@errors.cyclades.connection
@errors.plankton.id
@errors.plankton.metadata
def _run(self, image_id, key, val):
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.create_image_metadata(image_id, key, val))
+ self._print(
+ self.client.create_image_metadata(image_id, key, val), print_dict)
def main(self, image_id, key, val):
super(self.__class__, self)._run()
@command(image_cmds)
-class image_compute_properties_set(_init_cyclades):
+class image_compute_properties_set(_init_cyclades, _optional_json):
"""Add / update a set of properties for an image
proeprties must be given in the form key=value, e.v.
/image compute properties set <image-id> key1=val1 key2=val2
"""
- arguments = dict(
- json_output=FlagArgument('Show results in json', ('-j', '--json'))
- )
@errors.generic.all
@errors.cyclades.connection
@errors.plankton.id
def _run(self, image_id, keyvals):
- metadata = dict()
+ meta = dict()
for keyval in keyvals:
key, val = keyval.split('=')
- metadata[key] = val
- printer = print_json if self['json_output'] else print_dict
- printer(self.client.update_image_metadata(image_id, **metadata))
+ meta[key] = val
+ self._print(
+ self.client.update_image_metadata(image_id, **meta), print_dict)
def main(self, image_id, *key_equals_value):
super(self.__class__, self)._run()
from kamaki.cli.command_tree import CommandTree
from kamaki.cli.errors import raiseCLIError, CLISyntaxError
from kamaki.cli.utils import (
- format_size, to_bytes, print_dict, print_items, pretty_keys,
+ format_size, to_bytes, print_dict, print_items, pretty_keys, pretty_dict,
page_hold, bold, ask_user, get_path_size, print_json)
from kamaki.cli.argument import FlagArgument, ValueArgument, IntArgument
from kamaki.cli.argument import KeyValueArgument, DateArgument
from kamaki.cli.argument import ProgressBarArgument
-from kamaki.cli.commands import _command_init, errors, _optional_output_cmd
+from kamaki.cli.commands import _command_init, errors
+from kamaki.cli.commands import _optional_output_cmd, _optional_json
from kamaki.clients.pithos import PithosClient, ClientError
from kamaki.clients.astakos import AstakosClient
@command(pithos_cmds)
-class file_list(_file_container_command):
+class file_list(_file_container_command, _optional_json):
"""List containers, object trees or objects in a directory
Use with:
1 no parameters : containers in current account
exact_match=FlagArgument(
'Show only objects that match exactly with path',
'--exact-match'),
- enum=FlagArgument('Enumerate results', '--enumerate'),
- json_output=FlagArgument('show output in json', ('-j', '--json'))
+ enum=FlagArgument('Enumerate results', '--enumerate')
)
def print_objects(self, object_list):
if_unmodified_since=self['if_unmodified_since'],
until=self['until'],
show_only_shared=self['shared'])
- self.print_containers(r.json)
+ self._print(r.json, self.print_containers)
else:
prefix = self.path or self['prefix']
r = self.client.container_get(
until=self['until'],
meta=self['meta'],
show_only_shared=self['shared'])
- self.print_objects(r.json)
+ self._print(r.json, self.print_objects)
def main(self, container____path__=None):
super(self.__class__, self)._run(container____path__)
@command(pithos_cmds)
-class file_hashmap(_file_container_command):
+class file_hashmap(_file_container_command, _optional_json):
"""Get the hash-map of an object"""
arguments = dict(
if_match=ValueArgument('show output if ETags match', '--if-match'),
if_none_match=ValueArgument(
- 'show output if ETags match',
- '--if-none-match'),
+ 'show output if ETags match', '--if-none-match'),
if_modified_since=DateArgument(
- 'show output modified since then',
- '--if-modified-since'),
+ 'show output modified since then', '--if-modified-since'),
if_unmodified_since=DateArgument(
- 'show output unmodified since then',
- '--if-unmodified-since'),
+ 'show output unmodified since then', '--if-unmodified-since'),
object_version=ValueArgument(
- 'get the specific version',
- ('-O', '--object-version')),
- json_output=FlagArgument('show headers in json', ('-j', '--json'))
+ 'get the specific version', ('-O', '--object-version'))
)
@errors.generic.all
@errors.pithos.container
@errors.pithos.object_path
def _run(self):
- data = self.client.get_object_hashmap(
+ self._print(self.client.get_object_hashmap(
self.path,
version=self['object_version'],
if_match=self['if_match'],
if_none_match=self['if_none_match'],
if_modified_since=self['if_modified_since'],
- if_unmodified_since=self['if_unmodified_since'])
- printer = print_json if self['json_output'] else print_dict
- printer(data)
+ if_unmodified_since=self['if_unmodified_since']), print_dict)
def main(self, container___path):
super(self.__class__, self)._run(
"""
+def print_permissions(permissions_dict):
+ expected_keys = ('read', 'write')
+ if set(permissions_dict).issubset(expected_keys):
+ print_dict(permissions_dict)
+ else:
+ invalid_keys = set(permissions_dict.keys()).difference(expected_keys)
+ raiseCLIError(
+ 'Illegal permission keys: %s' % ', '.join(invalid_keys),
+ importance=1, details=[
+ 'Valid permission types: %s' % ' '.join(expected_keys)])
+
+
@command(pithos_cmds)
-class file_permissions_get(_file_container_command):
+class file_permissions_get(_file_container_command, _optional_json):
"""Get read and write permissions of an object"""
@errors.generic.all
@errors.pithos.container
@errors.pithos.object_path
def _run(self):
- r = self.client.get_object_sharing(self.path)
- print_dict(r)
+ self._print(
+ self.client.get_object_sharing(self.path), print_permissions)
def main(self, container___path):
super(self.__class__, self)._run(
@command(pithos_cmds)
-class file_info(_file_container_command):
+class file_info(_file_container_command, _optional_json):
"""Get detailed information for user account, containers or objects
to get account info: /file info
to get container info: /file info <container>
arguments = dict(
object_version=ValueArgument(
'show specific version \ (applies only for objects)',
- ('-O', '--object-version')),
- json_output=FlagArgument('show headers in json', ('-j', '--json'))
+ ('-O', '--object-version'))
)
@errors.generic.all
r = self.client.get_object_info(
self.path,
version=self['object_version'])
- printer = print_json if self['json_output'] else print_dict
- printer(r)
+ self._print(r, print_dict)
def main(self, container____path__=None):
super(self.__class__, self)._run(container____path__)
@command(pithos_cmds)
-class file_metadata_get(_file_container_command):
+class file_metadata_get(_file_container_command, _optional_json):
"""Get metadata for account, containers or objects"""
arguments = dict(
until=DateArgument('show metadata until then', '--until'),
object_version=ValueArgument(
'show specific version \ (applies only for objects)',
- ('-O', '--object-version')),
- json_output=FlagArgument('show headers in json', ('-j', '--json'))
+ ('-O', '--object-version'))
)
@errors.generic.all
@errors.pithos.object_path
def _run(self):
until = self['until']
+ r = None
if self.container is None:
if self['detail']:
r = self.client.get_account_info(until=until)
else:
r = self.client.get_account_meta(until=until)
r = pretty_keys(r, '-')
- print(bold(self.client.account))
elif self.path is None:
if self['detail']:
r = self.client.get_container_info(until=until)
version=self['object_version'])
r = pretty_keys(pretty_keys(r, '-'))
if r:
- printer = print_json if self['json_output'] else print_dict
- printer(r)
+ self._print(r, print_dict)
def main(self, container____path__=None):
super(self.__class__, self)._run(container____path__)
@command(pithos_cmds)
-class file_quota(_file_account_command):
+class file_quota(_file_account_command, _optional_json):
"""Get account quota"""
arguments = dict(
@errors.generic.all
@errors.pithos.connection
def _run(self):
- reply = self.client.get_account_quota()
- if not self['in_bytes']:
- for k in reply:
- reply[k] = format_size(reply[k])
- print_dict(pretty_keys(reply, '-'))
+
+ def pretty_print(output):
+ if not self['in_bytes']:
+ for k in output:
+ output[k] = format_size(output[k])
+ pretty_dict(output, '-')
+
+ self._print(self.client.get_account_quota(), pretty_print)
def main(self, custom_uuid=None):
super(self.__class__, self)._run(custom_account=custom_uuid)
@command(pithos_cmds)
-class file_containerlimit_get(_file_container_command):
+class file_containerlimit_get(_file_container_command, _optional_json):
"""Get container size limit"""
arguments = dict(
@errors.generic.all
@errors.pithos.container
def _run(self):
- reply = self.client.get_container_limit(self.container)
- if not self['in_bytes']:
- for k, v in reply.items():
- reply[k] = 'unlimited' if '0' == v else format_size(v)
- print_dict(pretty_keys(reply, '-'))
+
+ def pretty_print(output):
+ if not self['in_bytes']:
+ for k, v in output.items():
+ output[k] = 'unlimited' if '0' == v else format_size(v)
+ pretty_dict(output, '-')
+
+ self._print(
+ self.client.get_container_limit(self.container), pretty_print)
def main(self, container=None):
super(self.__class__, self)._run()
@command(pithos_cmds)
-class file_containerlimit_set(_file_account_command):
+class file_containerlimit_set(_file_account_command, _optional_output_cmd):
"""Set new storage limit for a container
By default, the limit is set in bytes
Users may specify a different unit, e.g:
@command(pithos_cmds)
-class file_versioning_get(_file_account_command):
+class file_versioning_get(_file_account_command, _optional_json):
"""Get versioning for account or container"""
@errors.generic.all
@errors.pithos.connection
@errors.pithos.container
def _run(self):
- if self.container:
- r = self.client.get_container_versioning(self.container)
- else:
- r = self.client.get_account_versioning()
- print_dict(r)
+ #if self.container:
+ # r = self.client.get_container_versioning(self.container)
+ #else:
+ # r = self.client.get_account_versioning()
+ self._print(
+ self.client.get_container_versioning(self.container) if (
+ self.container) else self.client.get_account_versioning(),
+ print_dict)
def main(self, container=None):
super(self.__class__, self)._run()
@command(pithos_cmds)
-class file_group_get(_file_account_command):
- """Get groups and group members"""
+class file_group_list(_file_account_command, _optional_json):
+ """list all groups and group members"""
@errors.generic.all
@errors.pithos.connection
def _run(self):
- r = self.client.get_account_group()
- print_dict(pretty_keys(r, '-'))
+ self._print(self.client.get_account_group(), pretty_dict, delim='-')
def main(self):
super(self.__class__, self)._run()
@command(pithos_cmds)
-class file_sharers(_file_account_command):
+class file_sharers(_file_account_command, _optional_json):
"""List the accounts that share objects with current user"""
arguments = dict(
@errors.pithos.connection
def _run(self):
accounts = self.client.get_sharing_accounts(marker=self['marker'])
- if self['detail']:
- print_items(accounts)
+ if self['json_output'] or self['detail']:
+ self._print(accounts)
else:
- print_items([acc['name'] for acc in accounts])
+ self._print([acc['name'] for acc in accounts])
def main(self):
super(self.__class__, self)._run()
self._run()
+def version_print(versions):
+ print_items([dict(id=vitem[0], created=strftime(
+ '%d-%m-%Y %H:%M:%S',
+ localtime(float(vitem[1])))) for vitem in versions])
+
+
@command(pithos_cmds)
-class file_versions(_file_container_command):
+class file_versions(_file_container_command, _optional_json):
"""Get the list of object versions
Deleted objects may still have versions that can be used to restore it and
get information about its previous state.
@errors.pithos.container
@errors.pithos.object_path
def _run(self):
- versions = self.client.get_object_versionlist(self.path)
- print_items([dict(id=vitem[0], created=strftime(
- '%d-%m-%Y %H:%M:%S',
- localtime(float(vitem[1])))) for vitem in versions])
+ self._print(
+ self.client.get_object_versionlist(self.path), version_print)
def main(self, container___path):
super(file_versions, self)._run(
print(dumps(data, indent=2))
+def pretty_dict(d, *args, **kwargs):
+ print_dict(pretty_keys(d, *args, **kwargs))
+
+
def print_dict(
d, exclude=(), ident=0,
with_enumeration=False, recursive_enumeration=False):
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
-from urllib2 import quote
+from urllib2 import quote, unquote
from urlparse import urlparse
from threading import Thread
from json import dumps, loads
recvlog.info('\n%s <-- %s <-- [req: %s]\n' % (
self, r, self.request))
self._request_performed = True
- self._status_code, self._status = r.status, r.reason
+ self._status_code, self._status = r.status, unquote(r.reason)
recvlog.info(
'%d %s\t[p: %s]' % (self.status_code, self.status, self))
self._headers = dict()
for k, v in r.getheaders():
if (not self.LOG_TOKEN) and k.lower() == 'x-auth-token':
continue
+ v = unquote(v)
self._headers[k] = v
recvlog.info(' %s: %s\t[p: %s]' % (k, v, self))
self._content = r.read()
def del_container_meta(self, metakey):
"""
:param metakey: (str) metadatum key
+
+ :returns: (dict) response headers
"""
r = self.container_post(update=True, metadata={metakey: ''})
return r.headers