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

Merge branch 'feature-store' into develop

parents fa984c2c 001200c3
......@@ -34,7 +34,13 @@
from kamaki.cli import command
from kamaki.cli.command_tree import CommandTree
from kamaki.cli.errors import raiseCLIError, CLISyntaxError
from kamaki.cli.utils import format_size, print_dict, pretty_keys, page_hold
from kamaki.cli.utils import (
format_size,
to_bytes,
print_dict,
pretty_keys,
page_hold,
ask_user)
from kamaki.cli.argument import FlagArgument, ValueArgument, IntArgument
from kamaki.cli.argument import KeyValueArgument, DateArgument
from kamaki.cli.argument import ProgressBarArgument
......@@ -83,7 +89,7 @@ def raise_connection_errors(e):
'- total quota: /store quota',
'- container quota: /store quota <container>',
'Users shall set a higher container quota, if available:',
'- /store setquota <limit in KB> <container>'
'- /store setquota <quota>[unit] <container>'
])
......@@ -1302,6 +1308,7 @@ class store_delete(_store_container_command):
arguments = dict(
until=DateArgument('remove history until that date', '--until'),
yes=FlagArgument('Do not prompt for permission', '--yes'),
recursive=FlagArgument(
'empty dir or container and delete (if dir)',
('-r', '--recursive'))
......@@ -1317,16 +1324,19 @@ class store_delete(_store_container_command):
def main(self, container____path__):
super(self.__class__, self).main(container____path__)
try:
if self.path is None:
self.client.del_container(
until=self['until'],
delimiter=self['delimiter'])
if (not self.path):
if self['yes'] or ask_user(
'Delete container %s ?' % self.container):
self.client.del_container(
until=self['until'],
delimiter=self['delimiter'])
else:
# self.client.delete_object(self.path)
self.client.del_object(
self.path,
until=self['until'],
delimiter=self['delimiter'])
if self['yes'] or ask_user(
'Delete %s:%s ?' % (self.container, self.path)):
self.client.del_object(
self.path,
until=self['until'],
delimiter=self['delimiter'])
except ClientError as err:
if err.status == 404:
if 'container' in ('%s' % err).lower():
......@@ -1358,10 +1368,16 @@ class store_purge(_store_container_command):
. container and data blocks are released and deleted
"""
arguments = dict(
yes=FlagArgument('Do not prompt for permission', '--yes'),
)
def main(self, container):
super(self.__class__, self).main(container)
try:
self.client.purge_container()
if self['yes'] or ask_user(
'Purge container %s?' % self.container):
self.client.purge_container()
except ClientError as err:
if err.status == 404:
if 'container' in ('%s' % err).lower():
......@@ -1765,7 +1781,11 @@ class store_delmeta(_store_container_command):
@command(pithos_cmds)
class store_quota(_store_account_command):
"""Get quota (in KB) for account or container"""
"""Get quota for account or container"""
arguments = dict(
in_bytes=FlagArgument('Show result in bytes', ('-b', '--bytes'))
)
def main(self, container=None):
super(self.__class__, self).main()
......@@ -1784,15 +1804,47 @@ class store_quota(_store_account_command):
raiseCLIError(err)
except Exception as err:
raiseCLIError(err)
if not self['in_bytes']:
for k in reply:
reply[k] = format_size(reply[k])
print_dict(pretty_keys(reply, '-'))
@command(pithos_cmds)
class store_setquota(_store_account_command):
"""Set new quota (in KB) for account or container"""
"""Set new quota for account or container
By default, quota is set in bytes
Users may specify a different unit, e.g:
/store setquota 2.3GB mycontainer
Accepted units: B, KiB (1024 B), KB (1000 B), MiB, MB, GiB, GB, TiB, TB
"""
def _calculate_quota(self, user_input):
quota = 0
try:
quota = int(user_input)
except ValueError:
index = 0
digits = [str(num) for num in range(0, 10)] + ['.']
while user_input[index] in digits:
index += 1
quota = user_input[:index]
format = user_input[index:]
try:
return to_bytes(quota, format)
except Exception as qe:
raiseCLIError(qe,
'Failed to convert %s to bytes' % user_input,
details=['Syntax: setquota <quota>[format] [container]',
'e.g.: setquota 2.3GB mycontainer',
'Acceptable formats:',
'(*1024): B, KiB, MiB, GiB, TiB',
'(*1000): B, KB, MB, GB, TB'])
return quota
def main(self, quota, container=None):
super(self.__class__, self).main()
quota = self._calculate_quota(quota)
try:
if container is None:
self.client.set_account_quota(quota)
......
......@@ -257,7 +257,7 @@ def print_items(items,
def format_size(size):
units = ('B', 'K', 'M', 'G', 'T')
units = ('B', 'KiB', 'MiB', 'GiB', 'TiB')
try:
size = float(size)
except ValueError as err:
......@@ -265,13 +265,37 @@ def format_size(size):
for unit in units:
if size < 1024:
break
size /= 1024
s = ('%.1f' % size)
if '.0' == s[-2:]:
s = s[:-2]
size /= 1024.0
s = ('%.2f' % size)
while '.' in s and s[-1] in ('0', '.'):
s = s[:-1]
return s + unit
def to_bytes(size, format):
"""
:param size: (float) the size in the given format
:param format: (case insensitive) KiB, KB, MiB, MB, GiB, GB, TiB, TB
:returns: (int) the size in bytes
"""
format = format.upper()
if format == 'B':
return int(size)
size = float(size)
units_dc = ('KB', 'MB', 'GB', 'TB')
units_bi = ('KIB', 'MIB', 'GIB', 'TIB')
factor = 1024 if format in units_bi else 1000 if format in units_dc else 0
if not factor:
raise ValueError('Invalid data size format %s' % format)
for prefix in ('K', 'M', 'G', 'T'):
size *= factor
if format.startswith(prefix):
break
return int(size)
def dict2file(d, f, depth=0):
for k, v in d.items():
f.write('%s%s: ' % ('\t' * depth, k))
......@@ -323,3 +347,16 @@ def split_input(line):
terms.append(ipart[2:-2])
terms += _sub_split(trivial_parts[-1])
return terms
def ask_user(msg, true_resp=['Y', 'y']):
"""Print msg and read user response
:param true_resp: (tuple of chars)
:returns: (bool) True if reponse in true responses, False otherwise
"""
stdout.write('%s (%s or enter for yes):' % (msg, ', '.join(true_resp)))
stdout.flush()
user_response = stdin.readline()
return user_response[0] in true_resp + ['\n']
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