Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / commissioning / callpoint.py @ 2005b18e

History | View | Annotate | Download (7.8 kB)

1 54069d1b Stavros Sachtouris
# Copyright 2012 GRNET S.A. All rights reserved.
2 54069d1b Stavros Sachtouris
#
3 54069d1b Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 54069d1b Stavros Sachtouris
# without modification, are permitted provided that the following
5 54069d1b Stavros Sachtouris
# conditions are met:
6 54069d1b Stavros Sachtouris
#
7 54069d1b Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 54069d1b Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 54069d1b Stavros Sachtouris
#      disclaimer.
10 54069d1b Stavros Sachtouris
#
11 54069d1b Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 54069d1b Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 54069d1b Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 54069d1b Stavros Sachtouris
#      provided with the distribution.
15 54069d1b Stavros Sachtouris
#
16 54069d1b Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 54069d1b Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 54069d1b Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 54069d1b Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 54069d1b Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 54069d1b Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 54069d1b Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 54069d1b Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 54069d1b Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 54069d1b Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 54069d1b Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 54069d1b Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 54069d1b Stavros Sachtouris
#
29 54069d1b Stavros Sachtouris
# The views and conclusions contained in the software and
30 54069d1b Stavros Sachtouris
# documentation are those of the authors and should not be
31 54069d1b Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 54069d1b Stavros Sachtouris
# or implied, of GRNET S.A.
33 54069d1b Stavros Sachtouris
34 54069d1b Stavros Sachtouris
35 b4368e33 Stavros Sachtouris
from kamaki.clients.commissioning.specificator import CanonifyException
36 b4368e33 Stavros Sachtouris
from kamaki.clients.commissioning.exception import CorruptedError
37 b4368e33 Stavros Sachtouris
from kamaki.clients.commissioning.exception import InvalidDataError
38 b4368e33 Stavros Sachtouris
from kamaki.clients.commissioning.exception import ReturnButFail
39 6764f588 Stavros Sachtouris
from kamaki.clients.commissioning.importing import imp_module
40 54069d1b Stavros Sachtouris
41 54069d1b Stavros Sachtouris
from re import compile as re_compile, sub as re_sub
42 54069d1b Stavros Sachtouris
43 b4368e33 Stavros Sachtouris
44 54069d1b Stavros Sachtouris
class Callpoint(object):
45 54069d1b Stavros Sachtouris
46 54069d1b Stavros Sachtouris
    api_spec = None
47 54069d1b Stavros Sachtouris
48 54069d1b Stavros Sachtouris
    CorruptedError = CorruptedError
49 54069d1b Stavros Sachtouris
    InvalidDataError = InvalidDataError
50 54069d1b Stavros Sachtouris
51 54069d1b Stavros Sachtouris
    original_calls = None
52 54069d1b Stavros Sachtouris
53 54069d1b Stavros Sachtouris
    def __init__(self, connection=None):
54 54069d1b Stavros Sachtouris
        from json import loads, dumps
55 54069d1b Stavros Sachtouris
56 54069d1b Stavros Sachtouris
        self.json_loads = loads
57 54069d1b Stavros Sachtouris
        self.json_dumps = dumps
58 54069d1b Stavros Sachtouris
        self.init_connection(connection)
59 54069d1b Stavros Sachtouris
        original_calls = {}
60 54069d1b Stavros Sachtouris
        self.original_calls = original_calls
61 54069d1b Stavros Sachtouris
        canonifier = self.api_spec
62 54069d1b Stavros Sachtouris
63 54069d1b Stavros Sachtouris
        if canonifier is None:
64 54069d1b Stavros Sachtouris
            m = "No api spec given to '%s'" % (type(self).__name__,)
65 54069d1b Stavros Sachtouris
            raise NotImplementedError(m)
66 54069d1b Stavros Sachtouris
67 54069d1b Stavros Sachtouris
        for call_name, call_doc in canonifier.call_docs():
68 54069d1b Stavros Sachtouris
            if hasattr(self, call_name):
69 54069d1b Stavros Sachtouris
70 54069d1b Stavros Sachtouris
                #raise ValueError(m)
71 54069d1b Stavros Sachtouris
                call_func = getattr(self, call_name)
72 54069d1b Stavros Sachtouris
                if not callable(call_func):
73 24ff0a35 Stavros Sachtouris
                    raise ValueError(' '.join([
74 24ff0a35 Stavros Sachtouris
                        "api spec '%s'," % type(canonifier).__name__,
75 24ff0a35 Stavros Sachtouris
                        "method '%s' is not a callable" % call_name,
76 24ff0a35 Stavros Sachtouris
                        "attribute in callpoint '%s'" % type(self).__name]))
77 54069d1b Stavros Sachtouris
78 54069d1b Stavros Sachtouris
                original_calls[call_name] = call_func
79 54069d1b Stavros Sachtouris
80 54069d1b Stavros Sachtouris
            def mk_call_func():
81 54069d1b Stavros Sachtouris
                local_call_name = call_name
82 6764f588 Stavros Sachtouris
83 54069d1b Stavros Sachtouris
                def call_func(**data):
84 54069d1b Stavros Sachtouris
                    return self.make_call(local_call_name, data)
85 54069d1b Stavros Sachtouris
86 54069d1b Stavros Sachtouris
                call_func.__name__ = call_name
87 54069d1b Stavros Sachtouris
                call_func.__doc__ = call_doc
88 54069d1b Stavros Sachtouris
                return call_func
89 54069d1b Stavros Sachtouris
90 54069d1b Stavros Sachtouris
            setattr(self, call_name, mk_call_func())
91 54069d1b Stavros Sachtouris
92 54069d1b Stavros Sachtouris
    def init_connection(self, connection):
93 54069d1b Stavros Sachtouris
        pass
94 54069d1b Stavros Sachtouris
95 54069d1b Stavros Sachtouris
    def commit(self):
96 54069d1b Stavros Sachtouris
        pass
97 54069d1b Stavros Sachtouris
98 54069d1b Stavros Sachtouris
    def rollback(self):
99 54069d1b Stavros Sachtouris
        pass
100 54069d1b Stavros Sachtouris
101 54069d1b Stavros Sachtouris
    def do_make_call(self, call_name, data):
102 54069d1b Stavros Sachtouris
        raise NotImplementedError
103 54069d1b Stavros Sachtouris
104 54069d1b Stavros Sachtouris
    def validate_call(self, call_name):
105 54069d1b Stavros Sachtouris
        return hasattr(self, call_name)
106 54069d1b Stavros Sachtouris
107 54069d1b Stavros Sachtouris
    def make_call_from_json_description(self, json_description):
108 54069d1b Stavros Sachtouris
        try:
109 54069d1b Stavros Sachtouris
            description = self.json_loads(json_description)
110 6764f588 Stavros Sachtouris
        except ValueError:
111 54069d1b Stavros Sachtouris
            m = "Cannot load json description"
112 54069d1b Stavros Sachtouris
            raise self.InvalidDataError(m)
113 54069d1b Stavros Sachtouris
114 54069d1b Stavros Sachtouris
        data = self.make_call_from_description(description)
115 54069d1b Stavros Sachtouris
        json_data = self.json_dumps(data) if data is not None else None
116 54069d1b Stavros Sachtouris
        return json_data
117 54069d1b Stavros Sachtouris
118 54069d1b Stavros Sachtouris
    def make_call_from_description(self, description):
119 54069d1b Stavros Sachtouris
        try:
120 54069d1b Stavros Sachtouris
            call_name = description['call_name']
121 54069d1b Stavros Sachtouris
            call_data = description['call_data']
122 54069d1b Stavros Sachtouris
        except (TypeError, KeyError), e:
123 54069d1b Stavros Sachtouris
            m = "Invalid description"
124 54069d1b Stavros Sachtouris
            raise self.InvalidDataError(m, e)
125 54069d1b Stavros Sachtouris
126 54069d1b Stavros Sachtouris
        return self.make_call(call_name, call_data)
127 54069d1b Stavros Sachtouris
128 54069d1b Stavros Sachtouris
    def make_call_from_json(self, call_name, json_data):
129 54069d1b Stavros Sachtouris
        if json_data:
130 54069d1b Stavros Sachtouris
            try:
131 54069d1b Stavros Sachtouris
                data = self.json_loads(json_data)
132 54069d1b Stavros Sachtouris
            except ValueError, e:
133 54069d1b Stavros Sachtouris
                m = "Cannot load json data"
134 54069d1b Stavros Sachtouris
                raise self.InvalidDataError(m, e)
135 54069d1b Stavros Sachtouris
        else:
136 54069d1b Stavros Sachtouris
            data = None
137 54069d1b Stavros Sachtouris
138 54069d1b Stavros Sachtouris
        data = self.make_call(call_name, data)
139 54069d1b Stavros Sachtouris
        json_data = self.json_dumps(data)
140 54069d1b Stavros Sachtouris
        return json_data
141 54069d1b Stavros Sachtouris
142 54069d1b Stavros Sachtouris
    def make_call(self, call_name, data):
143 54069d1b Stavros Sachtouris
        if call_name.startswith('_'):
144 54069d1b Stavros Sachtouris
            m = "Invalid call '%s'" % (call_name,)
145 54069d1b Stavros Sachtouris
            raise self.InvalidDataError(m)
146 54069d1b Stavros Sachtouris
147 54069d1b Stavros Sachtouris
        canonifier = self.api_spec
148 54069d1b Stavros Sachtouris
        try:
149 54069d1b Stavros Sachtouris
            data = canonifier.canonify_input(call_name, data)
150 54069d1b Stavros Sachtouris
        except CanonifyException, e:
151 54069d1b Stavros Sachtouris
            m = "Invalid input to call '%s'" % (call_name,)
152 54069d1b Stavros Sachtouris
            raise self.InvalidDataError(m, e)
153 54069d1b Stavros Sachtouris
154 54069d1b Stavros Sachtouris
        if not self.validate_call(call_name):
155 54069d1b Stavros Sachtouris
            m = "Cannot find specified call '%s'" % (call_name,)
156 54069d1b Stavros Sachtouris
            raise self.CorruptedError(m)
157 54069d1b Stavros Sachtouris
158 54069d1b Stavros Sachtouris
        call_func = self.original_calls.get(call_name, None)
159 54069d1b Stavros Sachtouris
        try:
160 54069d1b Stavros Sachtouris
            if call_func is None:
161 54069d1b Stavros Sachtouris
                data = self.do_make_call(call_name, data)
162 54069d1b Stavros Sachtouris
            else:
163 54069d1b Stavros Sachtouris
                data = call_func(**data)
164 54069d1b Stavros Sachtouris
            self.commit()
165 54069d1b Stavros Sachtouris
        except ReturnButFail, e:
166 54069d1b Stavros Sachtouris
            self.rollback()
167 54069d1b Stavros Sachtouris
            data = e.data
168 54069d1b Stavros Sachtouris
        except Exception, e:
169 54069d1b Stavros Sachtouris
            self.rollback()
170 54069d1b Stavros Sachtouris
            raise
171 54069d1b Stavros Sachtouris
172 54069d1b Stavros Sachtouris
        try:
173 54069d1b Stavros Sachtouris
            data = canonifier.canonify_output(call_name, data)
174 54069d1b Stavros Sachtouris
        except CanonifyException, e:
175 54069d1b Stavros Sachtouris
            m = "Invalid output from call '%s'" % (call_name,)
176 54069d1b Stavros Sachtouris
            raise self.CorruptedError(m, e)
177 54069d1b Stavros Sachtouris
178 54069d1b Stavros Sachtouris
        return data
179 54069d1b Stavros Sachtouris
180 54069d1b Stavros Sachtouris
181 54069d1b Stavros Sachtouris
def mkcallargs(**kw):
182 54069d1b Stavros Sachtouris
    return kw
183 54069d1b Stavros Sachtouris
184 54069d1b Stavros Sachtouris
185 54069d1b Stavros Sachtouris
versiontag_pattern = re_compile('[^a-zA-Z0-9_-]')
186 54069d1b Stavros Sachtouris
187 6764f588 Stavros Sachtouris
188 54069d1b Stavros Sachtouris
def mk_versiontag(version):
189 54069d1b Stavros Sachtouris
    if not version or version == 'v':
190 54069d1b Stavros Sachtouris
        return ''
191 54069d1b Stavros Sachtouris
192 54069d1b Stavros Sachtouris
    return '_' + re_sub(versiontag_pattern, '_', version)
193 54069d1b Stavros Sachtouris
194 54069d1b Stavros Sachtouris
195 54069d1b Stavros Sachtouris
def get_callpoint(pointname, version=None, automake=None, **kw):
196 54069d1b Stavros Sachtouris
197 54069d1b Stavros Sachtouris
    versiontag = mk_versiontag(version)
198 54069d1b Stavros Sachtouris
    components = pointname.split('.')
199 54069d1b Stavros Sachtouris
200 54069d1b Stavros Sachtouris
    appname = components[0]
201 54069d1b Stavros Sachtouris
    if len(components) < 2:
202 54069d1b Stavros Sachtouris
        raise ValueError("invalid pointname '%s'" % (pointname,))
203 54069d1b Stavros Sachtouris
204 54069d1b Stavros Sachtouris
    category = components[1]
205 54069d1b Stavros Sachtouris
    if not category or category not in ['clients', 'servers']:
206 54069d1b Stavros Sachtouris
        raise ValueError("invalid pointname '%s'" % (pointname,))
207 54069d1b Stavros Sachtouris
208 6764f588 Stavros Sachtouris
    modname = ('%s.callpoint.API_Callpoint%s' % (pointname, versiontag))
209 54069d1b Stavros Sachtouris
210 54069d1b Stavros Sachtouris
    try:
211 54069d1b Stavros Sachtouris
        API_Callpoint = imp_module(modname)
212 54069d1b Stavros Sachtouris
        return API_Callpoint
213 54069d1b Stavros Sachtouris
    except ImportError:
214 54069d1b Stavros Sachtouris
        if not automake:
215 54069d1b Stavros Sachtouris
            raise
216 54069d1b Stavros Sachtouris
217 54069d1b Stavros Sachtouris
    if category != 'clients':
218 6764f588 Stavros Sachtouris
        m = (
219 6764f588 Stavros Sachtouris
            "Can only auto-make callpoint in 'clients' not '%s'" % (category))
220 54069d1b Stavros Sachtouris
        raise ValueError(m)
221 54069d1b Stavros Sachtouris
222 54069d1b Stavros Sachtouris
    components = components[1:]
223 54069d1b Stavros Sachtouris
    if not components:
224 54069d1b Stavros Sachtouris
        raise ValueError("invalid pointname '%s'" % (pointname))
225 54069d1b Stavros Sachtouris
226 54069d1b Stavros Sachtouris
    pointname = '.'.join(components)
227 54069d1b Stavros Sachtouris
    if pointname == 'quotaholder':
228 54069d1b Stavros Sachtouris
        apiname = 'quotaholder.api.QuotaholderAPI'
229 54069d1b Stavros Sachtouris
    else:
230 54069d1b Stavros Sachtouris
        apiname = '%s.api.API_Spec%s' % (pointname, versiontag)
231 54069d1b Stavros Sachtouris
232 54069d1b Stavros Sachtouris
    API_Spec = imp_module(apiname)
233 54069d1b Stavros Sachtouris
234 54069d1b Stavros Sachtouris
    basename = 'commissioning.clients.%s.API_Callpoint' % (automake,)
235 54069d1b Stavros Sachtouris
    BaseCallpoint = imp_module(basename)
236 54069d1b Stavros Sachtouris
237 54069d1b Stavros Sachtouris
    stupidpython = (appname,
238 54069d1b Stavros Sachtouris
                    version if version is not None else 'v',
239 54069d1b Stavros Sachtouris
                    pointname,
240 54069d1b Stavros Sachtouris
                    automake)
241 54069d1b Stavros Sachtouris
242 54069d1b Stavros Sachtouris
    class AutoCallpoint(BaseCallpoint):
243 54069d1b Stavros Sachtouris
        appname, version, pointname, automake = stupidpython
244 54069d1b Stavros Sachtouris
        api_spec = API_Spec()
245 54069d1b Stavros Sachtouris
246 54069d1b Stavros Sachtouris
    return AutoCallpoint