Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / endpoints / qh.py @ e0fa2a89

History | View | Annotate | Download (9.7 kB)

1 fc1e2f02 Sofia Papagiannaki
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 5ce3ce4f Sofia Papagiannaki
#
3 fc1e2f02 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
4 fc1e2f02 Sofia Papagiannaki
# without modification, are permitted provided that the following
5 fc1e2f02 Sofia Papagiannaki
# conditions are met:
6 5ce3ce4f Sofia Papagiannaki
#
7 fc1e2f02 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
8 fc1e2f02 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
9 fc1e2f02 Sofia Papagiannaki
#      disclaimer.
10 5ce3ce4f Sofia Papagiannaki
#
11 fc1e2f02 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
12 fc1e2f02 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
13 fc1e2f02 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
14 fc1e2f02 Sofia Papagiannaki
#      provided with the distribution.
15 5ce3ce4f Sofia Papagiannaki
#
16 fc1e2f02 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 fc1e2f02 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 fc1e2f02 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 fc1e2f02 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 fc1e2f02 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 fc1e2f02 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 fc1e2f02 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 fc1e2f02 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 fc1e2f02 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 fc1e2f02 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 fc1e2f02 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 fc1e2f02 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
28 5ce3ce4f Sofia Papagiannaki
#
29 fc1e2f02 Sofia Papagiannaki
# The views and conclusions contained in the software and
30 fc1e2f02 Sofia Papagiannaki
# documentation are those of the authors and should not be
31 fc1e2f02 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
32 fc1e2f02 Sofia Papagiannaki
# or implied, of GRNET S.A.
33 fc1e2f02 Sofia Papagiannaki
34 fc1e2f02 Sofia Papagiannaki
import logging
35 bd4f356c Sofia Papagiannaki
import itertools
36 bd4f356c Sofia Papagiannaki
37 bd4f356c Sofia Papagiannaki
from functools import wraps
38 4fc7d569 Sofia Papagiannaki
from collections import namedtuple
39 fc1e2f02 Sofia Papagiannaki
40 fc1e2f02 Sofia Papagiannaki
from django.utils.translation import ugettext as _
41 fc1e2f02 Sofia Papagiannaki
42 30d92d1e Georgios D. Tsoukalas
from astakos.im.settings import (
43 0ea1f32b Georgios D. Tsoukalas
        QUOTAHOLDER_URL, QUOTAHOLDER_TOKEN, LOGGING_LEVEL)
44 fc1e2f02 Sofia Papagiannaki
45 30d92d1e Georgios D. Tsoukalas
if QUOTAHOLDER_URL:
46 c836d69f Georgios D. Tsoukalas
    from kamaki.clients.quotaholder import QuotaholderClient
47 8b59b8ea Sofia Papagiannaki
48 fc1e2f02 Sofia Papagiannaki
ENTITY_KEY = '1'
49 fc1e2f02 Sofia Papagiannaki
50 ae497612 Olga Brani
inf = float('inf')
51 ae497612 Olga Brani
52 fc1e2f02 Sofia Papagiannaki
logger = logging.getLogger(__name__)
53 fc1e2f02 Sofia Papagiannaki
54 ae497612 Olga Brani
inf = float('inf')
55 5ce3ce4f Sofia Papagiannaki
56 ee45eb81 Giorgos Korfiatis
clientkey = 'astakos'
57 ee45eb81 Giorgos Korfiatis
58 73fbaec4 Sofia Papagiannaki
_client = None
59 73fbaec4 Sofia Papagiannaki
def get_client():
60 73fbaec4 Sofia Papagiannaki
    global _client
61 73fbaec4 Sofia Papagiannaki
    if _client:
62 73fbaec4 Sofia Papagiannaki
        return _client
63 73fbaec4 Sofia Papagiannaki
    if not QUOTAHOLDER_URL:
64 73fbaec4 Sofia Papagiannaki
        return
65 73fbaec4 Sofia Papagiannaki
    _client = QuotaholderClient(QUOTAHOLDER_URL, token=QUOTAHOLDER_TOKEN)
66 52116521 Sofia Papagiannaki
    return _client
67 73fbaec4 Sofia Papagiannaki
68 bd4f356c Sofia Papagiannaki
def call(func_name):
69 b6852727 Olga Brani
    """Decorator function for Quotaholder client calls."""
70 bd4f356c Sofia Papagiannaki
    def decorator(payload_func):
71 bd4f356c Sofia Papagiannaki
        @wraps(payload_func)
72 73fbaec4 Sofia Papagiannaki
        def wrapper(entities=(), **kwargs):
73 bd4f356c Sofia Papagiannaki
            if not entities:
74 73fbaec4 Sofia Papagiannaki
                return ()
75 9a06d96f Olga Brani
76 30d92d1e Georgios D. Tsoukalas
            if not QUOTAHOLDER_URL:
77 73fbaec4 Sofia Papagiannaki
                return ()
78 9a06d96f Olga Brani
79 e0fa2a89 Kostas Papadimitriou
            c = get_client()
80 bd4f356c Sofia Papagiannaki
            func = c.__dict__.get(func_name)
81 bd4f356c Sofia Papagiannaki
            if not func:
82 73fbaec4 Sofia Papagiannaki
                return ()
83 9a06d96f Olga Brani
84 df2b0beb Sofia Papagiannaki
            data = payload_func(entities, **kwargs)
85 bd4f356c Sofia Papagiannaki
            if not data:
86 73fbaec4 Sofia Papagiannaki
                return data
87 9a06d96f Olga Brani
88 bd4f356c Sofia Papagiannaki
            funcname = func.__name__
89 bd4f356c Sofia Papagiannaki
            kwargs = {'context': {}, funcname: data}
90 bd4f356c Sofia Papagiannaki
            rejected = func(**kwargs)
91 bd4f356c Sofia Papagiannaki
            msg = _('%s: %s - Rejected: %s' % (funcname, data, rejected,))
92 bd4f356c Sofia Papagiannaki
            logger.log(LOGGING_LEVEL, msg)
93 73fbaec4 Sofia Papagiannaki
            return rejected
94 bd4f356c Sofia Papagiannaki
        return wrapper
95 bd4f356c Sofia Papagiannaki
    return decorator
96 bd4f356c Sofia Papagiannaki
97 9a06d96f Olga Brani
98 bd4f356c Sofia Papagiannaki
@call('set_quota')
99 df2b0beb Sofia Papagiannaki
def send_quota(users):
100 fc1e2f02 Sofia Papagiannaki
    data = []
101 fc1e2f02 Sofia Papagiannaki
    append = data.append
102 fc1e2f02 Sofia Papagiannaki
    for user in users:
103 670de92a Sofia Papagiannaki
        for resource, uplimit in user.quota.iteritems():
104 bd4f356c Sofia Papagiannaki
            key = ENTITY_KEY
105 bd4f356c Sofia Papagiannaki
            quantity = None
106 ae497612 Olga Brani
            capacity = uplimit if uplimit != inf else None
107 bd4f356c Sofia Papagiannaki
            import_limit = None
108 bd4f356c Sofia Papagiannaki
            export_limit = None
109 bd4f356c Sofia Papagiannaki
            flags = 0
110 9a06d96f Olga Brani
            args = (
111 e0fa2a89 Kostas Papadimitriou
                user.uuid, resource, key, quantity, capacity, import_limit,
112 9a06d96f Olga Brani
                export_limit, flags)
113 fc1e2f02 Sofia Papagiannaki
            append(args)
114 bd4f356c Sofia Papagiannaki
    return data
115 5ce3ce4f Sofia Papagiannaki
116 2a97d93b Giorgos Korfiatis
QuotaLimits = namedtuple('QuotaLimits', ('holder',
117 2a97d93b Giorgos Korfiatis
                                         'capacity',
118 2a97d93b Giorgos Korfiatis
                                         'import_limit',
119 2a97d93b Giorgos Korfiatis
                                         'export_limit'))
120 2a97d93b Giorgos Korfiatis
121 d2b32360 Giorgos Korfiatis
def qh_add_quota(serial, sub_list, add_list):
122 ee45eb81 Giorgos Korfiatis
    if not QUOTAHOLDER_URL:
123 ee45eb81 Giorgos Korfiatis
        return ()
124 ee45eb81 Giorgos Korfiatis
125 ee45eb81 Giorgos Korfiatis
    context = {}
126 ee45eb81 Giorgos Korfiatis
    c = get_client()
127 ee45eb81 Giorgos Korfiatis
128 d2b32360 Giorgos Korfiatis
    sub_quota = []
129 d2b32360 Giorgos Korfiatis
    sub_append = sub_quota.append
130 d2b32360 Giorgos Korfiatis
    add_quota = []
131 d2b32360 Giorgos Korfiatis
    add_append = add_quota.append
132 d2b32360 Giorgos Korfiatis
133 d2b32360 Giorgos Korfiatis
    for ql in sub_quota:
134 d2b32360 Giorgos Korfiatis
        args = (ql.holder, ql.resource, ENTITY_KEY,
135 d2b32360 Giorgos Korfiatis
                0, ql.capacity, ql.import_limit, ql.export_limit)
136 d2b32360 Giorgos Korfiatis
        sub_append(args)
137 d2b32360 Giorgos Korfiatis
138 d2b32360 Giorgos Korfiatis
    for ql in add_quota:
139 2a97d93b Giorgos Korfiatis
        args = (ql.holder, ql.resource, ENTITY_KEY,
140 2a97d93b Giorgos Korfiatis
                0, ql.capacity, ql.import_limit, ql.export_limit)
141 d2b32360 Giorgos Korfiatis
        add_append(args)
142 2a97d93b Giorgos Korfiatis
143 ee45eb81 Giorgos Korfiatis
    result = c.add_quota(context=context,
144 ee45eb81 Giorgos Korfiatis
                         clientkey=clientkey,
145 ee45eb81 Giorgos Korfiatis
                         serial=serial,
146 d2b32360 Giorgos Korfiatis
                         sub_quota=sub_quota,
147 d2b32360 Giorgos Korfiatis
                         add_quota=add_quota)
148 ee45eb81 Giorgos Korfiatis
149 ee45eb81 Giorgos Korfiatis
    return result
150 ee45eb81 Giorgos Korfiatis
151 ee45eb81 Giorgos Korfiatis
def qh_query_serials(serials):
152 ee45eb81 Giorgos Korfiatis
    if not QUOTAHOLDER_URL:
153 ee45eb81 Giorgos Korfiatis
        return ()
154 ee45eb81 Giorgos Korfiatis
155 ee45eb81 Giorgos Korfiatis
    context = {}
156 ee45eb81 Giorgos Korfiatis
    c = get_client()
157 ee45eb81 Giorgos Korfiatis
    result = c.query_serials(context=context,
158 ee45eb81 Giorgos Korfiatis
                             clientkey=clientkey,
159 ee45eb81 Giorgos Korfiatis
                             serials=serials)
160 ee45eb81 Giorgos Korfiatis
    return result
161 ee45eb81 Giorgos Korfiatis
162 ee45eb81 Giorgos Korfiatis
def qh_ack_serials(serials):
163 ee45eb81 Giorgos Korfiatis
    if not QUOTAHOLDER_URL:
164 ee45eb81 Giorgos Korfiatis
        return ()
165 ee45eb81 Giorgos Korfiatis
166 ee45eb81 Giorgos Korfiatis
    context = {}
167 ee45eb81 Giorgos Korfiatis
    c = get_client()
168 ee45eb81 Giorgos Korfiatis
    result = c.ack_serials(context=context,
169 ee45eb81 Giorgos Korfiatis
                           clientkey=clientkey,
170 ee45eb81 Giorgos Korfiatis
                           serials=serials)
171 ee45eb81 Giorgos Korfiatis
    return
172 5ce3ce4f Sofia Papagiannaki
173 bd4f356c Sofia Papagiannaki
@call('set_quota')
174 df2b0beb Sofia Papagiannaki
def send_resource_quantities(resources):
175 bd4f356c Sofia Papagiannaki
    data = []
176 bd4f356c Sofia Papagiannaki
    append = data.append
177 bd4f356c Sofia Papagiannaki
    for resource in resources:
178 bd4f356c Sofia Papagiannaki
        key = ENTITY_KEY
179 bd4f356c Sofia Papagiannaki
        quantity = resource.meta.filter(key='quantity') or None
180 bd4f356c Sofia Papagiannaki
        capacity = None
181 bd4f356c Sofia Papagiannaki
        import_limit = None
182 bd4f356c Sofia Papagiannaki
        export_limit = None
183 bd4f356c Sofia Papagiannaki
        flags = 0
184 bd4f356c Sofia Papagiannaki
        args = (resource.service, resource, key, quantity, capacity,
185 bd4f356c Sofia Papagiannaki
                import_limit, export_limit, flags)
186 bd4f356c Sofia Papagiannaki
        append(args)
187 bd4f356c Sofia Papagiannaki
    return data
188 bd4f356c Sofia Papagiannaki
189 bd4f356c Sofia Papagiannaki
190 bd4f356c Sofia Papagiannaki
@call('get_quota')
191 df2b0beb Sofia Papagiannaki
def get_quota(users):
192 fc1e2f02 Sofia Papagiannaki
    data = []
193 fc1e2f02 Sofia Papagiannaki
    append = data.append
194 fc1e2f02 Sofia Papagiannaki
    for user in users:
195 fc1e2f02 Sofia Papagiannaki
        try:
196 e0fa2a89 Kostas Papadimitriou
            entity = user.uuid
197 fc1e2f02 Sofia Papagiannaki
        except AttributeError:
198 fc1e2f02 Sofia Papagiannaki
            continue
199 fc1e2f02 Sofia Papagiannaki
        else:
200 bd4f356c Sofia Papagiannaki
            for r in user.quota.keys():
201 bd4f356c Sofia Papagiannaki
                args = entity, r, ENTITY_KEY
202 fc1e2f02 Sofia Papagiannaki
                append(args)
203 bd4f356c Sofia Papagiannaki
    return data
204 5ce3ce4f Sofia Papagiannaki
205 5ce3ce4f Sofia Papagiannaki
206 bd4f356c Sofia Papagiannaki
@call('create_entity')
207 df2b0beb Sofia Papagiannaki
def create_entities(entities, field=''):
208 fc1e2f02 Sofia Papagiannaki
    data = []
209 fc1e2f02 Sofia Papagiannaki
    append = data.append
210 bd4f356c Sofia Papagiannaki
    for entity in entities:
211 fc1e2f02 Sofia Papagiannaki
        try:
212 bd4f356c Sofia Papagiannaki
            entity = entity.__getattribute__(field)
213 fc1e2f02 Sofia Papagiannaki
        except AttributeError:
214 fc1e2f02 Sofia Papagiannaki
            continue
215 bd4f356c Sofia Papagiannaki
        owner = 'system'
216 bd4f356c Sofia Papagiannaki
        key = ENTITY_KEY
217 bd4f356c Sofia Papagiannaki
        ownerkey = ''
218 bd4f356c Sofia Papagiannaki
        args = entity, owner, key, ownerkey
219 bd4f356c Sofia Papagiannaki
        append(args)
220 bd4f356c Sofia Papagiannaki
    return data
221 5ce3ce4f Sofia Papagiannaki
222 5ce3ce4f Sofia Papagiannaki
223 df2b0beb Sofia Papagiannaki
def register_users(users):
224 bd4f356c Sofia Papagiannaki
    users, copy = itertools.tee(users)
225 e0fa2a89 Kostas Papadimitriou
    rejected = create_entities(entities=users, field='uuid')
226 bd4f356c Sofia Papagiannaki
    created = (e for e in copy if unicode(e) not in rejected)
227 73fbaec4 Sofia Papagiannaki
    return send_quota(created)
228 bd4f356c Sofia Papagiannaki
229 bd4f356c Sofia Papagiannaki
230 df2b0beb Sofia Papagiannaki
def register_resources(resources):
231 bd4f356c Sofia Papagiannaki
    resources, copy = itertools.tee(resources)
232 df2b0beb Sofia Papagiannaki
    rejected = create_entities(entities=resources, field='service')
233 bd4f356c Sofia Papagiannaki
    created = (e for e in copy if unicode(e) not in rejected)
234 73fbaec4 Sofia Papagiannaki
    return send_resource_quantities(created)
235 2925e285 root
236 2925e285 root
237 2925e285 root
from datetime import datetime
238 2925e285 root
239 2925e285 root
strptime = datetime.strptime
240 2925e285 root
timefmt = '%Y-%m-%dT%H:%M:%S.%f'
241 2925e285 root
242 476fdba1 root
SECOND_RESOLUTION = 1
243 476fdba1 root
244 9a06d96f Olga Brani
245 2925e285 root
def total_seconds(timedelta_object):
246 2925e285 root
    return timedelta_object.seconds + timedelta_object.days * 86400
247 2925e285 root
248 9a06d96f Olga Brani
249 476fdba1 root
def iter_timeline(timeline, before):
250 476fdba1 root
    if not timeline:
251 476fdba1 root
        return
252 476fdba1 root
253 476fdba1 root
    for t in timeline:
254 476fdba1 root
        yield t
255 476fdba1 root
256 476fdba1 root
    t = dict(t)
257 476fdba1 root
    t['issue_time'] = before
258 476fdba1 root
    yield t
259 476fdba1 root
260 9a06d96f Olga Brani
261 476fdba1 root
def _usage_units(timeline, after, before, details=0):
262 476fdba1 root
263 2925e285 root
    t_total = 0
264 476fdba1 root
    uu_total = 0
265 476fdba1 root
    t_after = strptime(after, timefmt)
266 476fdba1 root
    t_before = strptime(before, timefmt)
267 476fdba1 root
    t0 = t_after
268 476fdba1 root
    u0 = 0
269 2925e285 root
270 476fdba1 root
    for point in iter_timeline(timeline, before):
271 2925e285 root
        issue_time = point['issue_time']
272 2925e285 root
273 476fdba1 root
        if issue_time <= after:
274 476fdba1 root
            u0 = point['target_allocated_through']
275 2925e285 root
            continue
276 2925e285 root
277 476fdba1 root
        t = strptime(issue_time, timefmt) if issue_time <= before else t_before
278 476fdba1 root
        t_diff = int(total_seconds(t - t0) * SECOND_RESOLUTION)
279 2925e285 root
        t_total += t_diff
280 2925e285 root
        uu_cost = u0 * t_diff
281 2925e285 root
        uu_total += uu_cost
282 476fdba1 root
        t0 = t
283 476fdba1 root
        u0 = point['target_allocated_through']
284 2925e285 root
285 476fdba1 root
        target = point['target']
286 2925e285 root
        if details:
287 2925e285 root
            yield  (target,
288 2925e285 root
                    point['resource'],
289 2925e285 root
                    point['name'],
290 2925e285 root
                    issue_time,
291 2925e285 root
                    uu_cost,
292 2925e285 root
                    uu_total)
293 2925e285 root
294 2925e285 root
    if not t_total:
295 2925e285 root
        return
296 2925e285 root
297 2925e285 root
    yield  (target,
298 2925e285 root
            'total',
299 2925e285 root
            point['resource'],
300 2925e285 root
            issue_time,
301 9a06d96f Olga Brani
            uu_total / t_total,
302 2925e285 root
            uu_total)
303 2925e285 root
304 9a06d96f Olga Brani
305 476fdba1 root
def usage_units(timeline, after, before, details=0):
306 476fdba1 root
    return list(_usage_units(timeline, after, before, details=details))
307 2925e285 root
308 9a06d96f Olga Brani
309 476fdba1 root
def traffic_units(timeline, after, before, details=0):
310 82b05401 root
    tu_total = 0
311 82b05401 root
    target = None
312 82b05401 root
    issue_time = None
313 82b05401 root
314 82b05401 root
    for point in timeline:
315 82b05401 root
        issue_time = point['issue_time']
316 476fdba1 root
        if issue_time <= after:
317 476fdba1 root
            continue
318 476fdba1 root
        if issue_time > before:
319 476fdba1 root
            break
320 476fdba1 root
321 476fdba1 root
        target = point['target']
322 82b05401 root
        tu = point['target_allocated_through']
323 82b05401 root
        tu_total += tu
324 82b05401 root
325 82b05401 root
        if details:
326 82b05401 root
            yield  (target,
327 82b05401 root
                    point['resource'],
328 82b05401 root
                    point['name'],
329 82b05401 root
                    issue_time,
330 82b05401 root
                    tu,
331 82b05401 root
                    tu_total)
332 82b05401 root
333 82b05401 root
    if not tu_total:
334 82b05401 root
        return
335 82b05401 root
336 82b05401 root
    yield  (target,
337 82b05401 root
            'total',
338 82b05401 root
            point['resource'],
339 82b05401 root
            issue_time,
340 9a06d96f Olga Brani
            tu_total // len(timeline),
341 82b05401 root
            tu_total)
342 2925e285 root
343 9a06d96f Olga Brani
344 2925e285 root
def timeline_charge(entity, resource, after, before, details, charge_type):
345 2925e285 root
    key = '1'
346 2925e285 root
    if charge_type == 'charge_usage':
347 2925e285 root
        charge_units = usage_units
348 2925e285 root
    elif charge_type == 'charge_traffic':
349 2925e285 root
        charge_units = traffic_units
350 2925e285 root
    else:
351 2925e285 root
        m = 'charge type %s not supported' % charge_type
352 2925e285 root
        raise ValueError(m)
353 2925e285 root
354 30d92d1e Georgios D. Tsoukalas
    quotaholder = QuotaholderClient(QUOTAHOLDER_URL, token=QUOTAHOLDER_TOKEN)
355 2925e285 root
    timeline = quotaholder.get_timeline(
356 9a06d96f Olga Brani
        context={},
357 9a06d96f Olga Brani
        after=after,
358 9a06d96f Olga Brani
        before=before,
359 9a06d96f Olga Brani
        get_timeline=[[entity, resource, key]])
360 476fdba1 root
    cu = charge_units(timeline, after, before, details=details)
361 82b05401 root
    return cu