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 |