Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
kamaki
Commits
fa062062
Commit
fa062062
authored
Jan 15, 2013
by
Stavros Sachtouris
Browse files
Merge branch 'feature-quota' into develop
parents
81e34150
6c2a6f0d
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
kamaki/cli/commands/quotaholder_cli.py
0 → 100644
View file @
fa062062
# Copyright 2012 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, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this 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.
from
kamaki.cli.commissioning
import
commissioning_cli
from
kamaki.clients.quotaholder
import
QuotaholderClient
class
quotaholder_cli
(
commissioning_cli
):
def
__init__
(
self
):
self
.
client
=
QuotaholderClient
self
.
add_context
=
True
self
.
description
=
'Quotaholder description'
super
(
self
.
__class__
,
self
).
__init__
()
cli
=
quotaholder_cli
()
cli
.
generate_all
()
_commands
=
[
cli
.
ctree
]
kamaki/cli/commissioning.py
0 → 100644
View file @
fa062062
# Copyright 2012 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, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this 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.
from
kamaki.cli.commands
import
_command_init
from
kamaki.cli
import
command
from
kamaki.cli.command_tree
import
CommandTree
from
kamaki.cli.errors
import
CLIError
from
kamaki.clients.commissioning
import
CanonifyException
class
commissioning_cli
(
object
):
api_spec
=
None
appname
=
None
client
=
None
add_context
=
False
ctree
=
None
description
=
None
def
__init__
(
self
):
self
.
api_spec
=
self
.
client
.
api_spec
self
.
appname
=
self
.
client
.
appname
self
.
ctree
=
CommandTree
(
self
.
appname
,
self
.
description
)
def
generate_all
(
self
):
for
f
in
self
.
api_spec
.
call_names
():
c
=
self
.
mkClass
(
f
)
command
(
self
.
ctree
)(
c
)
def
mkClass
(
self
,
method
):
class
C
(
_command_init
):
__doc__
=
self
.
api_spec
.
get_doc
(
method
)
def
init
(
this
):
this
.
token
=
(
this
.
config
.
get
(
self
.
appname
,
'token'
)
or
this
.
config
.
get
(
'global'
,
'token'
))
this
.
base_url
=
(
this
.
config
.
get
(
self
.
appname
,
'url'
)
or
this
.
config
.
get
(
'global'
,
'url'
))
this
.
client
=
self
.
client
(
this
.
base_url
,
this
.
token
)
def
call
(
this
,
method
,
args
):
ctx
=
'=null '
if
self
.
add_context
else
''
arglist
=
'['
+
ctx
+
' '
.
join
(
args
)
+
']'
argdict
=
self
.
api_spec
.
parse
(
method
,
arglist
)
f
=
getattr
(
this
.
client
,
method
)
return
f
(
**
argdict
)
def
main
(
this
,
*
args
):
this
.
init
()
try
:
r
=
this
.
call
(
method
,
args
)
print
r
except
CanonifyException
,
e
:
params
=
self
.
api_spec
.
show_input_canonical
(
method
)
meth
=
method
.
replace
(
'_'
,
' '
)
m
=
'%s
\n
usage: %s %s'
%
(
e
,
meth
,
params
)
raise
CLIError
(
'%s: %s
\n
'
%
(
self
.
appname
,
m
))
except
Exception
as
e
:
raise
CLIError
(
'%s: %s
\n
'
%
(
self
.
appname
,
e
))
C
.
__name__
=
self
.
appname
+
'_'
+
method
return
C
kamaki/clients/commissioning/__init__.py
0 → 100644
View file @
fa062062
# Copyright 2012 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, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this 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.
# Import general commission framework
from
kamaki.clients.commissioning.exception
import
(
CallError
,
CorruptedError
,
InvalidDataError
,
ReturnButFail
,
register_exception
,
register_exceptions
)
from
kamaki.clients.commissioning.callpoint
import
(
Callpoint
,
mkcallargs
)
from
kamaki.clients.commissioning.specificator
import
(
Specificator
,
SpecifyException
,
Canonifier
,
CanonifyException
,
Canonical
,
Null
,
Nothing
,
Integer
,
Serial
,
Text
,
Bytes
,
Tuple
,
ListOf
,
Dict
,
Args
)
# Import standard implementations?
kamaki/clients/commissioning/callpoint.py
0 → 100644
View file @
fa062062
# Copyright 2012 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, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this 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.
from
kamaki.clients.commissioning.specificator
import
CanonifyException
from
kamaki.clients.commissioning.exception
import
CorruptedError
from
kamaki.clients.commissioning.exception
import
InvalidDataError
from
kamaki.clients.commissioning.exception
import
ReturnButFail
from
kamaki.clients.commissioning.importing
import
imp_module
from
re
import
compile
as
re_compile
,
sub
as
re_sub
class
Callpoint
(
object
):
api_spec
=
None
CorruptedError
=
CorruptedError
InvalidDataError
=
InvalidDataError
original_calls
=
None
def
__init__
(
self
,
connection
=
None
):
from
json
import
loads
,
dumps
self
.
json_loads
=
loads
self
.
json_dumps
=
dumps
self
.
init_connection
(
connection
)
original_calls
=
{}
self
.
original_calls
=
original_calls
canonifier
=
self
.
api_spec
if
canonifier
is
None
:
m
=
"No api spec given to '%s'"
%
(
type
(
self
).
__name__
,)
raise
NotImplementedError
(
m
)
for
call_name
,
call_doc
in
canonifier
.
call_docs
():
if
hasattr
(
self
,
call_name
):
# don't crash: wrap the function instead
#m = ( "Method '%s' defined both in natively "
# "in callpoint '%s' and in api spec '%s'" %
# (call_name,
# type(self).__name__,
# type(canonifier).__name__) )
#raise ValueError(m)
call_func
=
getattr
(
self
,
call_name
)
if
not
callable
(
call_func
):
m
=
(
"api spec '%s', method '%s' is not a "
"callable attribute in callpoint '%s'"
%
(
type
(
canonifier
).
__name__
,
call_name
,
type
(
self
).
__name
)
)
raise
ValueError
(
m
)
original_calls
[
call_name
]
=
call_func
def
mk_call_func
():
local_call_name
=
call_name
def
call_func
(
**
data
):
return
self
.
make_call
(
local_call_name
,
data
)
call_func
.
__name__
=
call_name
call_func
.
__doc__
=
call_doc
return
call_func
setattr
(
self
,
call_name
,
mk_call_func
())
def
init_connection
(
self
,
connection
):
pass
def
commit
(
self
):
pass
def
rollback
(
self
):
pass
def
do_make_call
(
self
,
call_name
,
data
):
raise
NotImplementedError
def
validate_call
(
self
,
call_name
):
return
hasattr
(
self
,
call_name
)
def
make_call_from_json_description
(
self
,
json_description
):
try
:
description
=
self
.
json_loads
(
json_description
)
except
ValueError
,
e
:
m
=
"Cannot load json description"
raise
self
.
InvalidDataError
(
m
)
data
=
self
.
make_call_from_description
(
description
)
json_data
=
self
.
json_dumps
(
data
)
if
data
is
not
None
else
None
return
json_data
def
make_call_from_description
(
self
,
description
):
try
:
call_name
=
description
[
'call_name'
]
call_data
=
description
[
'call_data'
]
except
(
TypeError
,
KeyError
),
e
:
m
=
"Invalid description"
raise
self
.
InvalidDataError
(
m
,
e
)
return
self
.
make_call
(
call_name
,
call_data
)
def
make_call_from_json
(
self
,
call_name
,
json_data
):
if
json_data
:
try
:
data
=
self
.
json_loads
(
json_data
)
except
ValueError
,
e
:
m
=
"Cannot load json data"
raise
self
.
InvalidDataError
(
m
,
e
)
else
:
data
=
None
data
=
self
.
make_call
(
call_name
,
data
)
json_data
=
self
.
json_dumps
(
data
)
return
json_data
def
make_call
(
self
,
call_name
,
data
):
if
call_name
.
startswith
(
'_'
):
m
=
"Invalid call '%s'"
%
(
call_name
,)
raise
self
.
InvalidDataError
(
m
)
canonifier
=
self
.
api_spec
try
:
data
=
canonifier
.
canonify_input
(
call_name
,
data
)
except
CanonifyException
,
e
:
m
=
"Invalid input to call '%s'"
%
(
call_name
,)
raise
self
.
InvalidDataError
(
m
,
e
)
if
not
self
.
validate_call
(
call_name
):
m
=
"Cannot find specified call '%s'"
%
(
call_name
,)
raise
self
.
CorruptedError
(
m
)
call_func
=
self
.
original_calls
.
get
(
call_name
,
None
)
try
:
if
call_func
is
None
:
data
=
self
.
do_make_call
(
call_name
,
data
)
else
:
data
=
call_func
(
**
data
)
self
.
commit
()
except
ReturnButFail
,
e
:
self
.
rollback
()
data
=
e
.
data
except
Exception
,
e
:
self
.
rollback
()
raise
try
:
data
=
canonifier
.
canonify_output
(
call_name
,
data
)
except
CanonifyException
,
e
:
m
=
"Invalid output from call '%s'"
%
(
call_name
,)
raise
self
.
CorruptedError
(
m
,
e
)
return
data
def
mkcallargs
(
**
kw
):
return
kw
versiontag_pattern
=
re_compile
(
'[^a-zA-Z0-9_-]'
)
def
mk_versiontag
(
version
):
if
not
version
or
version
==
'v'
:
return
''
return
'_'
+
re_sub
(
versiontag_pattern
,
'_'
,
version
)
def
get_callpoint
(
pointname
,
version
=
None
,
automake
=
None
,
**
kw
):
versiontag
=
mk_versiontag
(
version
)
components
=
pointname
.
split
(
'.'
)
appname
=
components
[
0
]
if
len
(
components
)
<
2
:
raise
ValueError
(
"invalid pointname '%s'"
%
(
pointname
,))
category
=
components
[
1
]
if
not
category
or
category
not
in
[
'clients'
,
'servers'
]:
raise
ValueError
(
"invalid pointname '%s'"
%
(
pointname
,))
modname
=
(
'%s.callpoint.API_Callpoint%s'
%
(
pointname
,
versiontag
))
try
:
API_Callpoint
=
imp_module
(
modname
)
return
API_Callpoint
except
ImportError
:
if
not
automake
:
raise
if
category
!=
'clients'
:
m
=
(
"Can only auto-make callpoint in 'clients' not '%s'"
%
(
category
,))
raise
ValueError
(
m
)
components
=
components
[
1
:]
if
not
components
:
raise
ValueError
(
"invalid pointname '%s'"
%
(
pointname
))
pointname
=
'.'
.
join
(
components
)
if
pointname
==
'quotaholder'
:
apiname
=
'quotaholder.api.QuotaholderAPI'
else
:
apiname
=
'%s.api.API_Spec%s'
%
(
pointname
,
versiontag
)
API_Spec
=
imp_module
(
apiname
)
basename
=
'commissioning.clients.%s.API_Callpoint'
%
(
automake
,)
BaseCallpoint
=
imp_module
(
basename
)
stupidpython
=
(
appname
,
version
if
version
is
not
None
else
'v'
,
pointname
,
automake
)
class
AutoCallpoint
(
BaseCallpoint
):
appname
,
version
,
pointname
,
automake
=
stupidpython
api_spec
=
API_Spec
()
return
AutoCallpoint
kamaki/clients/commissioning/exception.py
0 → 100644
View file @
fa062062
# Copyright 2012 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, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this 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.
def
str_or_utf8
(
s
):
if
isinstance
(
s
,
unicode
):
return
s
.
encode
(
'utf8'
)
return
str
(
s
)
class
CallError
(
Exception
):
exceptions
=
{}
def
__new__
(
cls
,
*
args
,
**
kw
):
call_error
=
kw
.
get
(
'call_error'
,
None
)
if
call_error
is
None
:
call_error
=
cls
.
__name__
else
:
call_error
=
str
(
call_error
)
cls
=
CallError
.
exceptions
.
get
(
call_error
,
cls
)
self
=
Exception
.
__new__
(
cls
)
return
self
def
__init__
(
self
,
*
args
,
**
kw
):
self
.
call_error
=
kw
.
pop
(
'call_error'
,
self
.
__class__
.
__name__
)
self
.
args
=
args
self
.
kwargs
=
kw
def
__str__
(
self
):
return
'
\n
--------
\n
'
.
join
(
str_or_utf8
(
x
)
for
x
in
self
.
args
)
def
__repr__
(
self
):
return
'%s(%s)'
%
(
self
.
__class__
.
__name__
,
','
.
join
(
str_or_utf8
(
x
)
for
x
in
self
.
args
))
@
classmethod
def
from_exception
(
cls
,
exc
):
args
=
None
try
:
args
=
tuple
(
exc
.
args
)
except
(
TypeError
,
AttributeError
),
e
:
pass
if
args
is
None
:
args
=
(
str
(
exc
),)
self
=
cls
(
*
args
,
call_error
=
exc
.
__class__
.
__name__
)
return
self
def
to_dict
(
self
):
return
{
'call_error'
:
self
.
call_error
,
'error_args'
:
(
self
.
args
,
self
.
kwargs
)}
@
classmethod
def
from_dict
(
cls
,
dictobj
):
args
=
None
try
:
if
'error_args'
in
dictobj
and
'call_error'
in
dictobj
:
args
=
dictobj
[
'error_args'
]
call_error
=
dictobj
[
'call_error'
]
except
TypeError
,
e
:
pass
if
args
is
None
:
args
=
(
str
(
dictobj
),)
call_error
=
'UnknownError'
kw
=
{}
else
:
args
,
kw
=
args
self
=
cls
(
*
args
,
call_error
=
call_error
,
**
kw
)
return
self
def
register_exceptions
(
*
exceptions
):
for
exception
in
exceptions
:
if
not
issubclass
(
exception
,
CallError
):
m
=
"Registering '%s': is not a CallError subclass"
%
(
exception
,)
raise
ValueError
(
m
)
CallError
.
exceptions
[
exception
.
__name__
]
=
exception
def
register_exception
(
exc
):
register_exceptions
(
exc
)
return
exc
@
register_exception
class
CorruptedError
(
CallError
):
pass
@
register_exception
class
InvalidDataError
(
CallError
):
pass
class
ReturnButFail
(
Exception
):
def
__init__
(
self
,
retval
=
None
):
self
.
data
=
retval
kamaki/clients/commissioning/importing.py
0 → 100644
View file @
fa062062
# Copyright 2012 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, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this 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