Commit 6764f588 authored by Stavros Sachtouris's avatar Stavros Sachtouris

Apply devflow ways of handling versions

Devflow is a GRNET system for handling versions and packaging the verious
GRNET.gr Synnefo software piecies
parent 8046291b
CHANGELOG for version 0.6.4 CHANGELOG for version 0.7
1. Clean up CLI error handling code 1. Clean up CLI error handling code
2. Unify and improve data size units presentation 2. Unify and improve data size units presentation
3. Ask for user permission at store-delete 3. Ask for user permission at store-delete
4. Intuitive semantics for store-move/copy/upload 4. Intuitive semantics for store-move/copy/download/upload (modified syntax and clients)
5. Dynamically limit max number of threads 5. Dynamically limit max number of threads
6. Various CLI and dependency fixes 6. Various CLI and dependency fixes
\ No newline at end of file
...@@ -31,4 +31,4 @@ ...@@ -31,4 +31,4 @@
# interpreted as representing official policies, either expressed # interpreted as representing official policies, either expressed
# or implied, of GRNET S.A. # or implied, of GRNET S.A.
__version__ = '0.6.4' from kamaki.version import __version__
...@@ -36,7 +36,7 @@ from kamaki.clients.commissioning.specificator import CanonifyException ...@@ -36,7 +36,7 @@ from kamaki.clients.commissioning.specificator import CanonifyException
from kamaki.clients.commissioning.exception import CorruptedError from kamaki.clients.commissioning.exception import CorruptedError
from kamaki.clients.commissioning.exception import InvalidDataError from kamaki.clients.commissioning.exception import InvalidDataError
from kamaki.clients.commissioning.exception import ReturnButFail from kamaki.clients.commissioning.exception import ReturnButFail
from kamaki.clients.commissioning.importing import imp_module from kamaki.clients.commissioning.importing import imp_module
from re import compile as re_compile, sub as re_sub from re import compile as re_compile, sub as re_sub
...@@ -76,17 +76,18 @@ class Callpoint(object): ...@@ -76,17 +76,18 @@ class Callpoint(object):
#raise ValueError(m) #raise ValueError(m)
call_func = getattr(self, call_name) call_func = getattr(self, call_name)
if not callable(call_func): if not callable(call_func):
m = ( "api spec '%s', method '%s' is not a " m = ("api spec '%s', method '%s' is not a "\
"callable attribute in callpoint '%s'" % "callable attribute in callpoint '%s'" %\
( type(canonifier).__name__, (type(canonifier).__name__,
call_name, call_name,
type(self).__name ) ) type(self).__name))
raise ValueError(m) raise ValueError(m)
original_calls[call_name] = call_func original_calls[call_name] = call_func
def mk_call_func(): def mk_call_func():
local_call_name = call_name local_call_name = call_name
def call_func(**data): def call_func(**data):
return self.make_call(local_call_name, data) return self.make_call(local_call_name, data)
...@@ -114,7 +115,7 @@ class Callpoint(object): ...@@ -114,7 +115,7 @@ class Callpoint(object):
def make_call_from_json_description(self, json_description): def make_call_from_json_description(self, json_description):
try: try:
description = self.json_loads(json_description) description = self.json_loads(json_description)
except ValueError, e: except ValueError:
m = "Cannot load json description" m = "Cannot load json description"
raise self.InvalidDataError(m) raise self.InvalidDataError(m)
...@@ -191,6 +192,7 @@ def mkcallargs(**kw): ...@@ -191,6 +192,7 @@ def mkcallargs(**kw):
versiontag_pattern = re_compile('[^a-zA-Z0-9_-]') versiontag_pattern = re_compile('[^a-zA-Z0-9_-]')
def mk_versiontag(version): def mk_versiontag(version):
if not version or version == 'v': if not version or version == 'v':
return '' return ''
...@@ -211,8 +213,7 @@ def get_callpoint(pointname, version=None, automake=None, **kw): ...@@ -211,8 +213,7 @@ def get_callpoint(pointname, version=None, automake=None, **kw):
if not category or category not in ['clients', 'servers']: if not category or category not in ['clients', 'servers']:
raise ValueError("invalid pointname '%s'" % (pointname,)) raise ValueError("invalid pointname '%s'" % (pointname,))
modname = ('%s.callpoint.API_Callpoint%s' modname = ('%s.callpoint.API_Callpoint%s' % (pointname, versiontag))
% (pointname, versiontag))
try: try:
API_Callpoint = imp_module(modname) API_Callpoint = imp_module(modname)
...@@ -222,7 +223,8 @@ def get_callpoint(pointname, version=None, automake=None, **kw): ...@@ -222,7 +223,8 @@ def get_callpoint(pointname, version=None, automake=None, **kw):
raise raise
if category != 'clients': if category != 'clients':
m = ("Can only auto-make callpoint in 'clients' not '%s'" % (category,)) m = (
"Can only auto-make callpoint in 'clients' not '%s'" % (category))
raise ValueError(m) raise ValueError(m)
components = components[1:] components = components[1:]
...@@ -250,4 +252,3 @@ def get_callpoint(pointname, version=None, automake=None, **kw): ...@@ -250,4 +252,3 @@ def get_callpoint(pointname, version=None, automake=None, **kw):
api_spec = API_Spec() api_spec = API_Spec()
return AutoCallpoint return AutoCallpoint
...@@ -68,7 +68,7 @@ class CallError(Exception): ...@@ -68,7 +68,7 @@ class CallError(Exception):
args = None args = None
try: try:
args = tuple(exc.args) args = tuple(exc.args)
except (TypeError, AttributeError), e: except (TypeError, AttributeError):
pass pass
if args is None: if args is None:
...@@ -87,7 +87,7 @@ class CallError(Exception): ...@@ -87,7 +87,7 @@ class CallError(Exception):
if 'error_args' in dictobj and 'call_error' in dictobj: if 'error_args' in dictobj and 'call_error' in dictobj:
args = dictobj['error_args'] args = dictobj['error_args']
call_error = dictobj['call_error'] call_error = dictobj['call_error']
except TypeError, e: except TypeError:
pass pass
if args is None: if args is None:
...@@ -100,25 +100,30 @@ class CallError(Exception): ...@@ -100,25 +100,30 @@ class CallError(Exception):
self = cls(*args, call_error=call_error, **kw) self = cls(*args, call_error=call_error, **kw)
return self return self
def register_exceptions(*exceptions): def register_exceptions(*exceptions):
for exception in exceptions: for exception in exceptions:
if not issubclass(exception, CallError): if not issubclass(exception, CallError):
m = "Registering '%s': is not a CallError subclass" % (exception,) m = "Registering '%s': is not a CallError subclass" % (exception,)
raise ValueError(m) raise ValueError(m)
CallError.exceptions[exception.__name__] = exception CallError.exceptions[exception.__name__] = exception
def register_exception(exc): def register_exception(exc):
register_exceptions(exc) register_exceptions(exc)
return exc return exc
@register_exception @register_exception
class CorruptedError(CallError): class CorruptedError(CallError):
pass pass
@register_exception @register_exception
class InvalidDataError(CallError): class InvalidDataError(CallError):
pass pass
class ReturnButFail(Exception): class ReturnButFail(Exception):
def __init__(self, retval=None): def __init__(self, retval=None):
self.data = retval self.data = retval
...@@ -35,6 +35,7 @@ from imp import find_module, load_module ...@@ -35,6 +35,7 @@ from imp import find_module, load_module
_modules = {} _modules = {}
def imp_module(fullname): def imp_module(fullname):
if fullname in _modules: if fullname in _modules:
return _modules[fullname] return _modules[fullname]
...@@ -77,5 +78,3 @@ def imp_module(fullname): ...@@ -77,5 +78,3 @@ def imp_module(fullname):
def list_modules(): def list_modules():
return sorted(_modules.keys()) return sorted(_modules.keys())
...@@ -46,6 +46,7 @@ try: ...@@ -46,6 +46,7 @@ try:
except ImportError: except ImportError:
from kamaki.clients.commissioning.utils.ordereddict import OrderedDict from kamaki.clients.commissioning.utils.ordereddict import OrderedDict
def shorts(s): def shorts(s):
if not isinstance(s, unicode): if not isinstance(s, unicode):
s = str(s) s = str(s)
...@@ -59,6 +60,7 @@ def shorts(s): ...@@ -59,6 +60,7 @@ def shorts(s):
class CanonifyException(Exception): class CanonifyException(Exception):
pass pass
class SpecifyException(Exception): class SpecifyException(Exception):
pass pass
...@@ -159,15 +161,15 @@ class Canonical(object): ...@@ -159,15 +161,15 @@ class Canonical(object):
joinchar = ',\n' joinchar = ',\n'
padchar = '\n' padchar = '\n'
args = [a.tostring( depth=depth, args = [a.tostring(
showopts=showopts, depth=depth,
multiline=multiline) for a in self.args] showopts=showopts,
args += [("%s=%s" % multiline=multiline) for a in self.args]
(k, v.tostring( depth=depth, args += [("%s=%s" % (k, v.tostring(
showopts=showopts, depth=depth,
multiline=multiline))) showopts=showopts,
multiline=multiline)))
for k, v in self.kw.items()] for k, v in self.kw.items()]
if showopts: if showopts:
args += [("%s=%s" % (k, str(v))) for k, v in self.opts.items()] args += [("%s=%s" % (k, str(v))) for k, v in self.opts.items()]
...@@ -194,6 +196,7 @@ class Canonical(object): ...@@ -194,6 +196,7 @@ class Canonical(object):
def _show(self): def _show(self):
return self.name return self.name
class Null(Canonical): class Null(Canonical):
def _check(self, item): def _check(self, item):
...@@ -207,13 +210,13 @@ class Integer(Canonical): ...@@ -207,13 +210,13 @@ class Integer(Canonical):
def _check(self, item): def _check(self, item):
try: try:
num = long(item) num = long(item)
except ValueError, e: except ValueError:
try: try:
num = long(item, 16) num = long(item, 16)
except Exception: except Exception:
m = "%s: cannot convert '%s' to long" % (self, shorts(item)) m = "%s: cannot convert '%s' to long" % (self, shorts(item))
raise CanonifyException(m) raise CanonifyException(m)
except TypeError, e: except TypeError:
m = "%s: cannot convert '%s' to long" % (self, shorts(item)) m = "%s: cannot convert '%s' to long" % (self, shorts(item))
raise CanonifyException(m) raise CanonifyException(m)
...@@ -246,11 +249,7 @@ class Integer(Canonical): ...@@ -246,11 +249,7 @@ class Integer(Canonical):
return long(minimum + r * (maximum - minimum)) return long(minimum + r * (maximum - minimum))
Serial = Integer(classname='Serial', null=True)
Serial = Integer(
classname = 'Serial',
null = True,
)
class Text(Canonical): class Text(Canonical):
...@@ -316,8 +315,7 @@ class Text(Canonical): ...@@ -316,8 +315,7 @@ class Text(Canonical):
matcher = self.matcher matcher = self.matcher
if matcher is not None: if matcher is not None:
match = matcher.match(item) match = matcher.match(item)
if ( match is None if ((not match) or (match.start(), match.end()) != (0, itemlen)):
or (match.start(), match.end()) != (0, itemlen) ):
m = ("%s: '%s' does not match '%s'" m = ("%s: '%s' does not match '%s'"
% (self, shorts(item), self.pat)) % (self, shorts(item), self.pat))
...@@ -344,7 +342,7 @@ class Text(Canonical): ...@@ -344,7 +342,7 @@ class Text(Canonical):
g = log(z, 2) g = log(z, 2)
r = random() * g r = random() * g
z = minlen + int(2**r) z = minlen + int(2 ** r)
s = u'' s = u''
for _ in xrange(z): for _ in xrange(z):
...@@ -410,9 +408,7 @@ class Bytes(Canonical): ...@@ -410,9 +408,7 @@ class Bytes(Canonical):
matcher = self.matcher matcher = self.matcher
if matcher is not None: if matcher is not None:
match = matcher.match(item) match = matcher.match(item)
if ( match is None if ((not match) or (match.start(), match.end()) != (0, itemlen)):
or (match.start(), match.end()) != (0, itemlen) ):
m = ("%s: '%s' does not match '%s'" m = ("%s: '%s' does not match '%s'"
% (self, shorts(item), self.pat)) % (self, shorts(item), self.pat))
raise CanonifyException(m) raise CanonifyException(m)
...@@ -438,7 +434,7 @@ class Bytes(Canonical): ...@@ -438,7 +434,7 @@ class Bytes(Canonical):
g = log(z, 2) g = log(z, 2)
r = random() * g r = random() * g
z = minlen + int(2**r) z = minlen + int(2 ** r)
s = u'' s = u''
for _ in xrange(z): for _ in xrange(z):
...@@ -475,7 +471,7 @@ class ListOf(Canonical): ...@@ -475,7 +471,7 @@ class ListOf(Canonical):
try: try:
items = iter(item) items = iter(item)
except TypeError, e: except TypeError:
m = "%s: %s is not iterable" % (self, shorts(item)) m = "%s: %s is not iterable" % (self, shorts(item))
raise CanonifyException(m) raise CanonifyException(m)
...@@ -502,6 +498,7 @@ class ListOf(Canonical): ...@@ -502,6 +498,7 @@ class ListOf(Canonical):
def _show(self): def _show(self):
return '[ ' + self.canonical.show() + ' ... ]' return '[ ' + self.canonical.show() + ' ... ]'
class Args(Canonical): class Args(Canonical):
def _unpack(self, item): def _unpack(self, item):
...@@ -524,8 +521,8 @@ class Args(Canonical): ...@@ -524,8 +521,8 @@ class Args(Canonical):
for i in range(position, arglen): for i in range(position, arglen):
key = keys[i] key = keys[i]
if not key in named_args.keys(): if not key in named_args.keys():
position = i + 1 position = i + 1
break break
else: else:
m = "Formal arguments exhausted" m = "Formal arguments exhausted"
raise AssertionError(m) raise AssertionError(m)
...@@ -535,8 +532,8 @@ class Args(Canonical): ...@@ -535,8 +532,8 @@ class Args(Canonical):
def _check(self, item): def _check(self, item):
try: try:
arglist = OrderedDict(item).items() OrderedDict(item).items()
except (TypeError, ValueError), e: except (TypeError, ValueError):
m = "%s: %s is not dict-able" % (self, shorts(item)) m = "%s: %s is not dict-able" % (self, shorts(item))
raise CanonifyException(m) raise CanonifyException(m)
...@@ -569,7 +566,7 @@ class Tuple(Canonical): ...@@ -569,7 +566,7 @@ class Tuple(Canonical):
def _check(self, item): def _check(self, item):
try: try:
items = list(item) items = list(item)
except TypeError, e: except TypeError:
m = "%s: %s is not iterable" % (self, shorts(item)) m = "%s: %s is not iterable" % (self, shorts(item))
raise CanonifyException(m) raise CanonifyException(m)
...@@ -578,7 +575,11 @@ class Tuple(Canonical): ...@@ -578,7 +575,11 @@ class Tuple(Canonical):
zc = len(canonicals) zc = len(canonicals)
if zi != zc: if zi != zc:
m = "%s: expecting %d elements, not %d (%s)" % (self, zc, zi, str(items)) m = "%s: expecting %d elements, not %d (%s)" % (
self,
zc,
zi,
str(items))
raise CanonifyException(m) raise CanonifyException(m)
g = (canonical(element) for canonical, element in zip(self.args, item)) g = (canonical(element) for canonical, element in zip(self.args, item))
...@@ -598,6 +599,7 @@ class Tuple(Canonical): ...@@ -598,6 +599,7 @@ class Tuple(Canonical):
strings = [x for x in [c.show() for c in canonicals] if x] strings = [x for x in [c.show() for c in canonicals] if x]
return '[ ' + ' '.join(strings) + ' ]' return '[ ' + ' '.join(strings) + ' ]'
class Dict(Canonical): class Dict(Canonical):
def _check(self, item): def _check(self, item):
...@@ -731,7 +733,7 @@ class Specificator(object): ...@@ -731,7 +733,7 @@ class Specificator(object):
deflen = len(defaults) deflen = len(defaults)
if arglen != deflen: if arglen != deflen:
a = (f.__name__, args[:arglen-deflen]) a = (f.__name__, args[:arglen - deflen])
m = "Unspecified arguments in '%s': %s" % a m = "Unspecified arguments in '%s': %s" % a
raise SpecifyException(m) raise SpecifyException(m)
...@@ -758,4 +760,3 @@ class Specificator(object): ...@@ -758,4 +760,3 @@ class Specificator(object):
def __call__(self): def __call__(self):
return self return self
# Copyright 2012-2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, self.list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, self.list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
...@@ -160,6 +160,7 @@ def argmap_encode(obj, output): ...@@ -160,6 +160,7 @@ def argmap_encode(obj, output):
output(']') output(']')
m = "Unsupported type '%s'" % (type(obj)) m = "Unsupported type '%s'" % (type(obj))
m += ''
def argmap_decode(inputf, s=None): def argmap_decode(inputf, s=None):
...@@ -216,7 +217,7 @@ def argmap_decode_args(inputf): ...@@ -216,7 +217,7 @@ def argmap_decode_args(inputf):
if s == ']': if s == ']':
if key is not None: if key is not None:
append((None, key)) append((None, key))
args.append(ARGMAP_MAGIC) args.append(ARGMAP_MAGIC)
return args, None return args, None
if s == '=': if s == '=':
...@@ -247,9 +248,10 @@ def argmap_check(obj): ...@@ -247,9 +248,10 @@ def argmap_check(obj):
return ARGMAP_MAGIC in obj return ARGMAP_MAGIC in obj
if hasattr(obj, '__len__'): if hasattr(obj, '__len__'):
length = len(obj) length = len(obj)
return length and obj[length-1] == ARGMAP_MAGIC return length and obj[length - 1] == ARGMAP_MAGIC
return False return False
def argmap_unzip_dict(argmap): def argmap_unzip_dict(argmap):
if not hasattr(argmap, 'keys'): if not hasattr(argmap, 'keys'):
m = "argmap unzip dict: not a dict" m = "argmap unzip dict: not a dict"
...@@ -262,6 +264,7 @@ def argmap_unzip_dict(argmap): ...@@ -262,6 +264,7 @@ def argmap_unzip_dict(argmap):
del kw[ARGMAP_MAGIC] del kw[ARGMAP_MAGIC]
return args, kw return args, kw
def argmap_unzip_list(argmap): def argmap_unzip_list(argmap):
if not argmap or argmap.pop() != ARGMAP_MAGIC: if not argmap or argmap.pop() != ARGMAP_MAGIC:
m = "argmap unzip list: magic not found" m = "argmap unzip list: magic not found"
...@@ -277,6 +280,7 @@ def argmap_unzip_list(argmap): ...@@ -277,6 +280,7 @@ def argmap_unzip_list(argmap):
kw[k] = v kw[k] = v
return args, kw return args, kw
def argmap_unzip(argmap): def argmap_unzip(argmap):
if hasattr(argmap, 'keys'): if hasattr(argmap, 'keys'):
return argmap_unzip_dict(argmap) return argmap_unzip_dict(argmap)
...@@ -286,9 +290,11 @@ def argmap_unzip(argmap): ...@@ -286,9 +290,11 @@ def argmap_unzip(argmap):
m = "argmap: cannot unzip type %s" % (type(argmap),) m = "argmap: cannot unzip type %s" % (type(argmap),)
raise ValueError(m) raise ValueError(m)
def argmap_zip_list(args, kw): def argmap_zip_list(args, kw):
return [(None, a) for a in args] + kw.items() + [ARGMAP_MAGIC] return [(None, a) for a in args] + kw.items() + [ARGMAP_MAGIC]
def argmap_zip_dict(args, kw):