c9043f67862d6749cf0010a19555e4c578b6552e
[myslice.git] / sla / slicetabsla.py
1 from __future__ import print_function
2
3 # this somehow is not used anymore - should it not be ?
4 import ast
5 from datetime import datetime
6 import json
7 import pytz
8 from django.template import RequestContext
9 from django.shortcuts import render_to_response
10 from django.shortcuts import render
11 from django import forms
12 import re
13
14 from unfold.loginrequired import LoginRequiredView, FreeAccessView
15 from unfold.page import Page
16 from sla.slaclient import restclient
17 from sla.slaclient import wsag_model
18 import wsag_helper
19 from myslice.theme import ThemeView
20 # from sla import SLAPlugin
21 from django.core.urlresolvers import reverse
22 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
23
24 import slaclient.service.fed4fire.fed4fireservice as fed4fireservice
25 from django.http import HttpResponse
26
27 from myslice.settings import logger, SLA_COLLECTOR_URL
28
29
30 # class AgreementsFilter(object):
31 # def __init__(self, status=None, provider=None, consumer=None):
32 #         self.status = status
33 #         self.provider = provider
34 #         self.consumer = consumer
35 #
36 #     def __repr__(self):
37 #         return "<AgreementsFilter(status={}, provider={}, consumer={})>".format(
38 #             self.status, self.provider, self.consumer
39 #         )
40 #
41 #     @staticmethod
42 #     def _check(expectedvalue, actualvalue):
43 #         if expectedvalue is None or expectedvalue == '':
44 #             return True
45 #         else:
46 #             return actualvalue == expectedvalue
47 #
48 #     def check(self, agreement):
49 #         """Check if this agreement satisfy the filter.
50 #
51 #         The agreement must be previously annotated
52 #         """
53 #         guaranteestatus = agreement.guaranteestatus
54 #         provider = agreement.context.provider
55 #         consumer = agreement.context.consumer
56 #         return (
57 #             AgreementsFilter._check(self.status, guaranteestatus) and
58 #             AgreementsFilter._check(self.provider, provider) and
59 #             AgreementsFilter._check(self.consumer, consumer)
60 #         )
61
62
63 # class FilterForm(forms.Form):
64 #     _attrs = {'class': 'form-control'}
65 #     exclude = ()
66 #     status = forms.ChoiceField(
67 #         choices=[
68 #             ('', 'All'),
69 #             (wsag_model.AgreementStatus.StatusEnum.FULFILLED, 'Fulfilled'),
70 #             (wsag_model.AgreementStatus.StatusEnum.VIOLATED, 'Violated'),
71 #             (wsag_model.AgreementStatus.StatusEnum.NON_DETERMINED, 'Non determined')],
72 #         widget=forms.Select(attrs=_attrs),
73 #         required=False
74 #     )
75 #     provider = forms.CharField(
76 #         widget=forms.TextInput(attrs=_attrs),
77 #         required=False
78 #     )
79 #     consumer = forms.CharField(
80 #         widget=forms.TextInput(attrs=_attrs),
81 #         required=False
82 #     )
83
84
85 class SLAView(FreeAccessView, ThemeView):
86     template_name = 'slice-tab-sla.html'
87
88     def get(self, request, slicename):
89
90         page = Page(request)
91
92         # logger.debug("SLA slice name: {}".format(slicename))
93
94         # consumer_id = None
95         agreement_id = None
96         enforcements = {}
97         violations = {}
98         keys = ['provider', 'agreement',
99                 'date', 'status', 'result',
100                 'ok', 'slivers']
101         ag_info = []
102
103         # filter_ = None
104         # form = FilterForm(request.GET)
105         # if form.is_valid():
106         #     filter_ = _get_filter_from_form(form)
107
108         # consumer_id = _get_consumer_id(request)
109
110         # agreements = _get_agreements(agreement_id, consumer_id=consumer_id, filter_=filter_)
111         agreements = _get_agreements_by_slice(slicename)
112
113         for agreement in agreements:
114             row = []
115             provider = agreement.context.provider
116             row.append(provider)  # Provider
117             row.append(agreement)  # Agreement
118             row.append(agreement.context.time_formatted())  # Date
119
120             enf = _get_enforcement(agreement.agreement_id, provider)
121             # logger.debug("SLA guarantee status {}: {}".format(agreement.agreement_id,
122             #                                                   agreement.guaranteestatus))
123
124             if enf.enabled == 'true':
125                 row.append('Evaluating')  # Status
126                 row.append('')  # Result
127                 row.append('')  # Ok
128             else:
129                 if agreement.guaranteestatus == "NON_DETERMINED":
130                     row.append('Provisioned')  # Status
131                     row.append('')  # Result
132                     row.append('')  # Ok
133
134                 else:
135                     row.append('Finished')  # Status
136
137                     violations_list = _get_agreement_violations(agreement.agreement_id, provider, "GT_Performance")
138
139                     if len(violations_list) > 0:
140                         value = '%.2f' % float(violations_list[0].actual_value)
141                         row.append('%d' % (float(value) * 100))  # Result
142                     else:
143                         row.append('100')  # Result
144
145                     if agreement.guaranteestatus == "VIOLATED":
146                         row.append('false')  # Ok
147
148                     if agreement.guaranteestatus == "FULFILLED":
149                         row.append('true')  # Ok
150
151             for _, terms in agreement.guaranteeterms.items():
152                 try:
153                     s = ast.literal_eval(terms.scopes[0].scope.lstrip())
154                     logger.debug('SLA scope: {}'.format(s))
155                     row.append(s)
156                     break
157                 except Exception as e:
158                     logger.debug("SLA EXCEPTION: {}".format(e.message))
159
160             ag_info.append(dict(zip(keys, row)))
161
162         template_env = {}
163         # write something of our own instead
164         # more general variables expected in the template
165         template_env['title'] = 'SLA Agreements'
166         template_env['agreements'] = agreements
167         template_env['username'] = request.user
168         template_env['slicename'] = slicename
169         template_env['enforcements'] = enforcements
170         template_env['last_violation_list'] = violations
171         template_env['ag_info'] = ag_info
172
173         # the prelude object in page contains a summary of the requirements() for all plugins
174         # define {js,css}_{files,chunks}
175         prelude_env = page.prelude_env()
176         template_env.update(prelude_env)
177
178         return render_to_response(self.template_name, template_env, context_instance=RequestContext(request))
179
180
181 # class AgreementsFilter(object):
182 #     def __init__(self, status=None, provider=None, consumer=None):
183 #         self.status = status
184 #         self.provider = provider
185 #         self.consumer = consumer
186 #
187 #     def __repr__(self):
188 #         return "<AgreementsFilter(status={}, provider={}, consumer={})>".format(
189 #             self.status, self.provider, self.consumer
190 #         )
191 #
192 #     @staticmethod
193 #     def _check(expectedvalue, actualvalue):
194 #         if expectedvalue is None or expectedvalue == '':
195 #             return True
196 #         else:
197 #             return actualvalue == expectedvalue
198 #
199 #     def check(self, agreement):
200 #         """Check if this agreement satisfy the filter.
201 #
202 #         The agreement must be previously annotated
203 #         """
204 #         guaranteestatus = agreement.guaranteestatus
205 #         provider = agreement.context.provider
206 #         consumer = agreement.context.consumer
207 #         return (
208 #             AgreementsFilter._check(self.status, guaranteestatus) and
209 #             AgreementsFilter._check(self.provider, provider) and
210 #             AgreementsFilter._check(self.consumer, consumer)
211 #         )
212
213
214 # class ContactForm(forms.Form):
215 #     subject = forms.CharField(max_length=100)
216 #     message = forms.CharField()
217 #     sender = forms.EmailField()
218 #     cc_myself = forms.BooleanField(required=False)
219
220
221 def _get_agreements_client():
222     return restclient.Factory.agreements()
223
224
225 def _get_violations_client():
226     return restclient.Factory.violations()
227
228
229 def _get_enforcements_client():
230     return restclient.Factory.enforcements()
231
232
233 def _get_consumer_id(request):
234     return request.user
235
236
237 def _get_agreement(agreement_id):
238     agreements_client = _get_agreements_client()
239     agreement, response = agreements_client.getbyid(agreement_id)
240     return agreement
241
242
243 def _get_enforcement(agreement_id, testbed):
244     enforcements_client = _get_enforcements_client()
245     enforcement, response = enforcements_client.getbyagreement(agreement_id, testbed)
246     return enforcement
247
248
249 # def _get_filter_from_form(form):
250 #
251 #     data = form.cleaned_data
252 #     result = AgreementsFilter(
253 #         data["status"], data["provider"], data["consumer"])
254 #     return result
255
256 def agreement_term_violations(request, agreement_id, guarantee_name):
257     page = Page(request)
258     prelude_env = page.prelude_env()
259
260     annotator = wsag_helper.AgreementAnnotator()
261     agreement = _get_agreement(agreement_id)
262     violations = _get_agreement_violations(agreement_id, guarantee_name)
263     annotator.annotate_agreement(agreement)
264
265     slicename = request.POST.get('slicename')
266
267     paginator = Paginator(violations, 25)  # Show 25 violations per page
268     page_num = request.GET.get('page')
269
270     try:
271         violation_page = paginator.page(page_num)
272     except PageNotAnInteger:
273         # If page is not an integer, deliver first page.
274         violation_page = paginator.page(1)
275     except EmptyPage:
276         # If page is out of range (e.g. 9999), deliver first page.
277         violation_page = paginator.page(1)
278
279     context = {
280         'agreement_id': agreement_id,
281         'guarantee_term': agreement.guaranteeterms[guarantee_name],
282         'violations': violation_page,
283         'agreement': agreement,
284         'slicename': slicename,
285         'last_violation': violations[-1].actual_value
286     }
287
288     context.update(prelude_env)
289
290     return render_to_response('violations_template.html', context, context_instance=RequestContext(request))
291
292
293 #     return render(request, 'violations_template.html', context)
294
295
296 # TODO Change function to class
297 def agreement_details(request, agreement_id):
298     page = Page(request)
299     prelude_env = page.prelude_env()
300
301     annotator = wsag_helper.AgreementAnnotator()
302     agreement = _get_agreement(agreement_id)
303     violations = _get_agreement_violations(agreement_id)
304     status = _get_agreement_status(agreement_id)
305     annotator.annotate_agreement(agreement, status, violations)
306
307     violations_by_date = wsag_helper.get_violations_bydate(violations)
308     context = {
309         'agreement_id': agreement_id,
310         'agreement': agreement,
311         'status': status,
312         'violations_by_date': violations_by_date
313     }
314
315     context.update(prelude_env)
316
317     return render_to_response('violations_template.html', context, context_instance=RequestContext(request))
318     #return render(request, 'agreement_detail.html', context)
319
320
321 # def _get_agreements(agreement_id, slice=None, provider_id=None, consumer_id=None, filter_=None):
322 #
323 #     agreements_client = _get_agreements_client()
324 #     if agreement_id is None:
325 #         if consumer_id is not None:
326 #             agreements, response = agreements_client.getbyconsumer(consumer_id)
327 #         elif provider_id is not None:
328 #             agreements, response = agreements_client.getbyprovider(provider_id)
329 #         elif slice is not None:
330 #             agreements_client = _get_agreements_client("slice")
331 #             agreements, response = agreements_client.getbyslice(slice)
332 #         else:
333 #             raise ValueError(
334 #                 "Invalid values: consumer_id and provider_id are None")
335 #     else:
336 #         agreement, response = agreements_client.getbyid(agreement_id)
337 #         agreements = [agreement]
338 #
339 #     annotator = wsag_helper.AgreementAnnotator()
340 #     for agreement in agreements:
341 #         id_ = agreement.agreement_id
342 #         testbed = agreement.context.provider
343 #         status = _get_agreement_status(id_, testbed)
344 #         annotator.annotate_agreement(agreement, status)
345 #
346 #     if filter_ is not None:
347 #         print "FILTERING ", repr(filter_)
348 #         agreements = filter(filter_.check, agreements)
349 #     else:
350 #         print "NOT FILTERING"
351 #     return agreements
352
353 def _get_agreements_by_slice(slice):
354     agreements_client = _get_agreements_client()
355     agreements, response = agreements_client.getbyslice(slice)
356
357     annotator = wsag_helper.AgreementAnnotator()
358     for agreement in agreements:
359         id_ = agreement.agreement_id
360         testbed = agreement.context.provider
361         status = _get_agreement_status(id_, testbed)
362         annotator.annotate_agreement(agreement, status)
363
364     return agreements
365
366
367 # def _get_agreements_by_consumer(consumer_id):
368 #
369 #     agreements_client = _get_agreements_client()
370 #     agreements, response = agreements_client.getbyconsumer(consumer_id)
371 #     return agreements
372
373 def _get_agreement_status(agreement_id, testbed):
374     agreements_client = _get_agreements_client()
375     status, response = agreements_client.getstatus(agreement_id, testbed)
376     return status
377
378
379 def _get_agreement_violations(agreement_id, testbed, term=None):
380     violations_client = _get_violations_client()
381     violations, response = violations_client.getbyagreement(agreement_id, testbed, term)
382     return violations
383
384
385 class Testbeds(FreeAccessView, ThemeView):
386     def get(self, request, *args, **kwargs):
387         c = restclient.Client(SLA_COLLECTOR_URL)
388         #url = settings.SLA_MANAGER_URL.replace("/sla","")
389         #c = restclient.Client(url)
390         # print "**** URL ******", url
391         SLAtestbeds = c.get("testbeds/")
392         # Future work: get SLA description for each testbed
393
394         return HttpResponse(SLAtestbeds.text, content_type="application/json", status=SLAtestbeds.status_code)
395
396
397 class CreateAgreement(LoginRequiredView, ThemeView):
398     def post(self, request, *args, **kwargs):
399
400         c = restclient.Client(SLA_COLLECTOR_URL)
401         data = request.POST.copy()
402
403         testbed_urn_regex = r"\+(.*?)\+"
404         pattern = re.compile(testbed_urn_regex)
405         testbed_urn = pattern.search(data["SLIVER_INFO_AGGREGATE_URN"]).group(1)
406
407         # Fix for django QueryDict list parameters
408         slivers = data.getlist("SLIVER_INFO_URN[]")
409         data["SLIVER_INFO_URN"] = slivers
410         del data["SLIVER_INFO_URN[]"]
411
412         # Timestamp to ISO date + timezone
413         tstmp = data["SLIVER_INFO_EXPIRATION"]
414         dt = datetime.fromtimestamp(float(tstmp))
415         # gmt_2 = pytz.timezone("Etc/GMT-2")
416         # dlocal = gmt_2.localize(dt).isoformat()
417         dlocal = dt.isoformat() + "CET" # FIXME: hardcoded for demo purposes
418         data["SLIVER_INFO_EXPIRATION"] = dlocal
419
420         # logger.debug("SLA Agreement parameters: {}".format(data.dict()))
421         # import pdb; pdb.set_trace()
422
423         try:
424             response = c.post("agreementslist/", data=json.dumps(data),
425                               headers={"accept": "application/json",
426                                  "content-type": "application/json"})
427         except Exception as e:
428             # import traceback, sys
429             #
430             # traceback.print_exc(file=sys.stdout)
431             logger.debug("SLA Error: CreateAgreement {}".format(e.message))
432
433         return HttpResponse(response.text, status=response.status_code)