blob: a633819eb1197ea04253a078b17700812125e421 [file] [log] [blame]
svavilap022f56f2015-12-04 14:05:39 -05001import requests
2from six.moves import urllib
3import urllib2
4import pytz
5import datetime
6from rest_framework.decorators import api_view
7from rest_framework.response import Response
8from rest_framework.reverse import reverse
9from rest_framework import serializers
10from rest_framework import generics
11from rest_framework.views import APIView
12from core.models import *
Scott Bakerb487e302015-12-31 11:13:21 -080013from services.ceilometer.models import *
svavilap022f56f2015-12-04 14:05:39 -050014from django.forms import widgets
15from django.utils import datastructures
16from django.utils.translation import ugettext_lazy as _
17from django.utils import timezone
svavilap022f56f2015-12-04 14:05:39 -050018from django.core.exceptions import PermissionDenied
Scott Baker0ae266e2016-01-14 15:30:20 -080019from xos.logger import observer_logger as logger
svavilap022f56f2015-12-04 14:05:39 -050020
21# This REST API endpoint provides information that the ceilometer view needs to display
svavilap022f56f2015-12-04 14:05:39 -050022
23def getTenantCeilometerProxyURL(user):
24 monitoring_channel = None
25 for obj in MonitoringChannel.get_tenant_objects().all():
26 if (obj.creator.username == user.username):
27 monitoring_channel = obj
28 break
29 if not monitoring_channel:
30 raise XOSMissingField("Monitoring channel is missing for this tenant...Create one and invoke this REST API")
31 #TODO: Wait until URL is completely UP
32 while True:
33 try:
34 response = urllib2.urlopen(monitoring_channel.ceilometer_url,timeout=1)
35 break
36 except urllib2.HTTPError, e:
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -050037 logger.info('SRIKANTH: HTTP error %(reason)s' % {'reason':e.reason})
svavilap022f56f2015-12-04 14:05:39 -050038 break
39 except urllib2.URLError, e:
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -050040 logger.info('SRIKANTH: URL error %(reason)s' % {'reason':e.reason})
svavilap022f56f2015-12-04 14:05:39 -050041 pass
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -050042 logger.info("SRIKANTH: Ceilometer proxy URL for user %(user)s is %(url)s" % {'user':user.username,'url':monitoring_channel.ceilometer_url})
svavilap022f56f2015-12-04 14:05:39 -050043 return monitoring_channel.ceilometer_url
44
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -050045def getTenantControllerTenantMap(user, slice=None):
svavilap022f56f2015-12-04 14:05:39 -050046 tenantmap={}
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -050047 if not slice:
48 slices = Slice.objects.filter(creator=user)
49 else:
50 slices = [slice]
51 for s in slices:
52 for cs in s.controllerslices.all():
svavilap022f56f2015-12-04 14:05:39 -050053 if cs.tenant_id:
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -050054 tenantmap[cs.tenant_id] = {"slice": cs.slice.name}
55 if cs.slice.service:
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -050056 tenantmap[cs.tenant_id]["service"] = cs.slice.service.name
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -050057 else:
58 logger.warn("SRIKANTH: Slice %(slice)s is not associated with any service" % {'slice':cs.slice.name})
59 tenantmap[cs.tenant_id]["service"] = "Other"
svavilap022f56f2015-12-04 14:05:39 -050060 return tenantmap
61
62def build_url(path, q, params=None):
63 """Convert list of dicts and a list of params to query url format.
64
65 This will convert the following:
66 "[{field=this,op=le,value=34},
67 {field=that,op=eq,value=foo,type=string}],
68 ['foo=bar','sna=fu']"
69 to:
70 "?q.field=this&q.field=that&
71 q.op=le&q.op=eq&
72 q.type=&q.type=string&
73 q.value=34&q.value=foo&
74 foo=bar&sna=fu"
75 """
76 if q:
77 query_params = {'q.field': [],
78 'q.value': [],
79 'q.op': [],
80 'q.type': []}
81
82 for query in q:
83 for name in ['field', 'op', 'value', 'type']:
84 query_params['q.%s' % name].append(query.get(name, ''))
85
86 # Transform the dict to a sequence of two-element tuples in fixed
87 # order, then the encoded string will be consistent in Python 2&3.
88 new_qparams = sorted(query_params.items(), key=lambda x: x[0])
89 path += "?" + urllib.parse.urlencode(new_qparams, doseq=True)
90
91 if params:
92 for p in params:
93 path += '&%s' % p
94 elif params:
95 path += '?%s' % params[0]
96 for p in params[1:]:
97 path += '&%s' % p
98 return path
99
100def concat_url(endpoint, url):
101 """Concatenate endpoint and final URL.
102
103 E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
104 "http://keystone/v2.0/tokens".
105
106 :param endpoint: the base URL
107 :param url: the final URL
108 """
109 return "%s/%s" % (endpoint.rstrip("/"), url.strip("/"))
110
111def resource_list(request, query=None, ceilometer_url=None, ceilometer_usage_object=None):
112 """List the resources."""
113 url = concat_url(ceilometer_url, build_url('/v2/resources', query))
114 try:
115 response = requests.get(url)
116 except requests.exceptions.RequestException as e:
117 raise e
118 return response.json()
119
120def sample_list(request, meter_name, ceilometer_url=None, query=None, limit=None):
121 """List the samples for this meters."""
122 params = ['limit=%s' % limit] if limit else []
123 url = concat_url(ceilometer_url, build_url('/v2/samples', query, params))
124 try:
125 response = requests.get(url)
126 except requests.exceptions.RequestException as e:
127 raise e
128 return response.json()
129
130def meter_list(request, ceilometer_url=None, query=None):
131 """List the user's meters."""
132 url = concat_url(ceilometer_url, build_url('/v2/meters', query))
133 try:
134 response = requests.get(url)
135 except requests.exceptions.RequestException as e:
136 raise e
137 return response.json()
138
139
140def statistic_list(request, meter_name, ceilometer_url=None, query=None, period=None):
141 """List of statistics."""
142 p = ['period=%s' % period] if period else []
143 url = concat_url(ceilometer_url, build_url('/v2/meters/' + meter_name + '/statistics', query, p))
144 try:
145 response = requests.get(url)
146 except requests.exceptions.RequestException as e:
147 raise e
148 return response.json()
149
150def diff_lists(a, b):
151 if not a:
152 return []
153 elif not b:
154 return a
155 else:
156 return list(set(a) - set(b))
157
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -0500158def get_resource_map(request, ceilometer_url, query=None):
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500159 resource_map = {}
160 try:
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -0500161 resources = resource_list(request, ceilometer_url=ceilometer_url, query=query)
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500162 for r in resources:
163 if 'display_name' in r['metadata']:
164 name = r['metadata']['display_name']
165 elif 'name' in r['metadata']:
166 name = r['metadata']['name']
167 else:
168 name = r['resource_id']
169 resource_map[r['resource_id']] = name
170 except requests.exceptions.RequestException as e:
171 raise e
172
173 return resource_map
174
svavilap022f56f2015-12-04 14:05:39 -0500175class Meters(object):
176 """Class for listing of available meters.
177
178 It is listing meters defined in this class that are available
179 in Ceilometer meter_list.
180
181 It is storing information that is not available in Ceilometer, i.e.
182 label, description.
183
184 """
185
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -0500186 def __init__(self, request=None, ceilometer_meter_list=None, ceilometer_url=None, query=None, tenant_map=None, resource_map=None):
svavilap022f56f2015-12-04 14:05:39 -0500187 # Storing the request.
188 self._request = request
189 self.ceilometer_url = ceilometer_url
190 self.tenant_map = tenant_map
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500191 self.resource_map = resource_map
svavilap022f56f2015-12-04 14:05:39 -0500192
193 # Storing the Ceilometer meter list
194 if ceilometer_meter_list:
195 self._ceilometer_meter_list = ceilometer_meter_list
196 else:
197 try:
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -0500198 meter_query=[]
199 if query:
200 meter_query = query
201 self._ceilometer_meter_list = meter_list(request, self.ceilometer_url, meter_query)
svavilap022f56f2015-12-04 14:05:39 -0500202 except requests.exceptions.RequestException as e:
203 self._ceilometer_meter_list = []
204 raise e
205
206 # Storing the meters info categorized by their services.
207 self._nova_meters_info = self._get_nova_meters_info()
208 self._neutron_meters_info = self._get_neutron_meters_info()
209 self._glance_meters_info = self._get_glance_meters_info()
210 self._cinder_meters_info = self._get_cinder_meters_info()
211 self._swift_meters_info = self._get_swift_meters_info()
212 self._kwapi_meters_info = self._get_kwapi_meters_info()
213 self._ipmi_meters_info = self._get_ipmi_meters_info()
214 self._vcpe_meters_info = self._get_vcpe_meters_info()
215 self._sdn_meters_info = self._get_sdn_meters_info()
216
217 # Storing the meters info of all services together.
218 all_services_meters = (self._nova_meters_info,
219 self._neutron_meters_info,
220 self._glance_meters_info,
221 self._cinder_meters_info,
222 self._swift_meters_info,
223 self._kwapi_meters_info,
224 self._ipmi_meters_info,
225 self._vcpe_meters_info,
226 self._sdn_meters_info)
227 self._all_meters_info = {}
228 for service_meters in all_services_meters:
229 self._all_meters_info.update(dict([(meter_name, meter_info)
230 for meter_name, meter_info
231 in service_meters.items()]))
232
233 # Here will be the cached Meter objects, that will be reused for
234 # repeated listing.
235 self._cached_meters = {}
236
237 def list_all(self, only_meters=None, except_meters=None):
238 """Returns a list of meters based on the meters names.
239
240 :Parameters:
241 - `only_meters`: The list of meter names we want to show.
242 - `except_meters`: The list of meter names we don't want to show.
243 """
244
245 return self._list(only_meters=only_meters,
246 except_meters=except_meters)
247
248 def list_nova(self, except_meters=None):
249 """Returns a list of meters tied to nova.
250
251 :Parameters:
252 - `except_meters`: The list of meter names we don't want to show.
253 """
254
255 return self._list(only_meters=self._nova_meters_info.keys(),
256 except_meters=except_meters)
257
258 def list_neutron(self, except_meters=None):
259 """Returns a list of meters tied to neutron.
260
261 :Parameters:
262 - `except_meters`: The list of meter names we don't want to show.
263 """
264
265 return self._list(only_meters=self._neutron_meters_info.keys(),
266 except_meters=except_meters)
267
268 def list_glance(self, except_meters=None):
269 """Returns a list of meters tied to glance.
270
271 :Parameters:
272 - `except_meters`: The list of meter names we don't want to show.
273 """
274
275 return self._list(only_meters=self._glance_meters_info.keys(),
276 except_meters=except_meters)
277
278 def list_cinder(self, except_meters=None):
279 """Returns a list of meters tied to cinder.
280
281 :Parameters:
282 - `except_meters`: The list of meter names we don't want to show.
283 """
284
285 return self._list(only_meters=self._cinder_meters_info.keys(),
286 except_meters=except_meters)
287
288 def list_swift(self, except_meters=None):
289 """Returns a list of meters tied to swift.
290
291 :Parameters:
292 - `except_meters`: The list of meter names we don't want to show.
293 """
294
295 return self._list(only_meters=self._swift_meters_info.keys(),
296 except_meters=except_meters)
297
298 def list_kwapi(self, except_meters=None):
299 """Returns a list of meters tied to kwapi.
300
301 :Parameters:
302 - `except_meters`: The list of meter names we don't want to show.
303 """
304
305 return self._list(only_meters=self._kwapi_meters_info.keys(),
306 except_meters=except_meters)
307
308 def list_ipmi(self, except_meters=None):
309 """Returns a list of meters tied to ipmi
310
311 :Parameters:
312 - `except_meters`: The list of meter names we don't want to show
313 """
314
315 return self._list(only_meters=self._ipmi_meters_info.keys(),
316 except_meters=except_meters)
317
318 def list_vcpe(self, except_meters=None):
319 """Returns a list of meters tied to vcpe service
320
321 :Parameters:
322 - `except_meters`: The list of meter names we don't want to show
323 """
324
325 return self._list(only_meters=self._vcpe_meters_info.keys(),
326 except_meters=except_meters)
327
328 def list_sdn(self, except_meters=None):
329 """Returns a list of meters tied to sdn service
330
331 :Parameters:
332 - `except_meters`: The list of meter names we don't want to show
333 """
334
335 return self._list(only_meters=self._sdn_meters_info.keys(),
336 except_meters=except_meters)
337
338 def list_other_services(self, except_meters=None):
339 """Returns a list of meters tied to ipmi
340
341 :Parameters:
342 - `except_meters`: The list of meter names we don't want to show
343 """
344 other_service_meters = [m for m in self._ceilometer_meter_list
345 if m.name not in self._all_meters_info.keys()]
346 other_service_meters = diff_lists(other_service_meters, except_meters)
347
348 meters = []
349 for meter in other_service_meters:
350 self._cached_meters[meter.name] = meter
351 meters.append(meter)
352 return meters
353
354 def _list(self, only_meters=None, except_meters=None):
355 """Returns a list of meters based on the meters names.
356
357 :Parameters:
358 - `only_meters`: The list of meter names we want to show.
359 - `except_meters`: The list of meter names we don't want to show.
360 """
361
362 # Get all wanted meter names.
363 if only_meters:
364 meter_names = only_meters
365 else:
366 meter_names = [meter_name for meter_name
367 in self._all_meters_info.keys()]
368
369 meter_names = diff_lists(meter_names, except_meters)
370 # Collect meters for wanted meter names.
371 return self._get_meters(meter_names)
372
373 def _get_meters(self, meter_names):
374 """Obtain meters based on meter_names.
375
376 The meters that do not exist in Ceilometer meter list are left out.
377
378 :Parameters:
379 - `meter_names`: A list of meter names we want to fetch.
380 """
381
382 meters = []
383 for meter_name in meter_names:
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500384 meter_candidates = self._get_meter(meter_name)
385 if meter_candidates:
386 meters.extend(meter_candidates)
svavilap022f56f2015-12-04 14:05:39 -0500387 return meters
388
389 def _get_meter(self, meter_name):
390 """Obtains a meter.
391
392 Obtains meter either from cache or from Ceilometer meter list
393 joined with statically defined meter info like label and description.
394
395 :Parameters:
396 - `meter_name`: A meter name we want to fetch.
397 """
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500398 meter_candidates = self._cached_meters.get(meter_name, None)
399 if not meter_candidates:
svavilap022f56f2015-12-04 14:05:39 -0500400 meter_candidates = [m for m in self._ceilometer_meter_list
401 if m["name"] == meter_name]
402
403 if meter_candidates:
404 meter_info = self._all_meters_info.get(meter_name, None)
405 if meter_info:
406 label = meter_info["label"]
407 description = meter_info["description"]
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500408 meter_category = meter_info["type"]
svavilap022f56f2015-12-04 14:05:39 -0500409 else:
410 label = ""
411 description = ""
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500412 meter_category = "Other"
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500413 for meter in meter_candidates:
414 meter["label"] = label
415 meter["description"] = description
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500416 meter["category"] = meter_category
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500417 if meter["project_id"] in self.tenant_map.keys():
418 meter["slice"] = self.tenant_map[meter["project_id"]]["slice"]
419 meter["service"] = self.tenant_map[meter["project_id"]]["service"]
420 else:
421 meter["slice"] = meter["project_id"]
422 meter["service"] = "Other"
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -0500423 if meter["resource_id"] in self.resource_map.keys():
424 meter["resource_name"] = self.resource_map[meter["resource_id"]]
svavilap022f56f2015-12-04 14:05:39 -0500425
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500426 self._cached_meters[meter_name] = meter_candidates
svavilap022f56f2015-12-04 14:05:39 -0500427
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500428 return meter_candidates
svavilap022f56f2015-12-04 14:05:39 -0500429
430 def _get_nova_meters_info(self):
431 """Returns additional info for each meter.
432
433 That will be used for augmenting the Ceilometer meter.
434 """
435
436 # TODO(lsmola) Unless the Ceilometer will provide the information
437 # below, I need to define it as a static here. I will be joining this
438 # to info that I am able to obtain from Ceilometer meters, hopefully
439 # some day it will be supported all.
440 meters_info = datastructures.SortedDict([
441 ("instance", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500442 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500443 'label': '',
444 'description': _("Existence of instance"),
445 }),
446 ("instance:<type>", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500447 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500448 'label': '',
449 'description': _("Existence of instance <type> "
450 "(openstack types)"),
451 }),
452 ("memory", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500453 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500454 'label': '',
455 'description': _("Volume of RAM"),
456 }),
457 ("memory.usage", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500458 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500459 'label': '',
460 'description': _("Volume of RAM used"),
461 }),
462 ("cpu", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500463 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500464 'label': '',
465 'description': _("CPU time used"),
466 }),
467 ("cpu_util", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500468 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500469 'label': '',
470 'description': _("Average CPU utilization"),
471 }),
472 ("vcpus", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500473 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500474 'label': '',
475 'description': _("Number of VCPUs"),
476 }),
Srikanth Vavilapalli6ff55982016-01-22 14:35:50 -0500477 ("disk.read.requests", {
478 'type': _("Nova"),
479 'label': '',
480 'description': _("Number of read requests"),
481 }),
482 ("disk.write.requests", {
483 'type': _("Nova"),
484 'label': '',
485 'description': _("Number of write requests"),
486 }),
487 ("disk.read.bytes", {
488 'type': _("Nova"),
489 'label': '',
490 'description': _("Volume of reads"),
491 }),
492 ("disk.write.bytes", {
493 'type': _("Nova"),
494 'label': '',
495 'description': _("Volume of writes"),
496 }),
497 ("disk.read.requests.rate", {
498 'type': _("Nova"),
499 'label': '',
500 'description': _("Average rate of read requests"),
501 }),
502 ("disk.write.requests.rate", {
503 'type': _("Nova"),
504 'label': '',
505 'description': _("Average rate of write requests"),
506 }),
507 ("disk.read.bytes.rate", {
508 'type': _("Nova"),
509 'label': '',
510 'description': _("Average rate of reads"),
511 }),
512 ("disk.write.bytes.rate", {
513 'type': _("Nova"),
514 'label': '',
515 'description': _("Average volume of writes"),
516 }),
517 ("disk.root.size", {
518 'type': _("Nova"),
519 'label': '',
520 'description': _("Size of root disk"),
521 }),
522 ("disk.ephemeral.size", {
523 'type': _("Nova"),
524 'label': '',
525 'description': _("Size of ephemeral disk"),
526 }),
527 ("network.incoming.bytes", {
528 'type': _("Nova"),
529 'label': '',
530 'description': _("Number of incoming bytes "
531 "on the network for a VM interface"),
532 }),
533 ("network.outgoing.bytes", {
534 'type': _("Nova"),
535 'label': '',
536 'description': _("Number of outgoing bytes "
537 "on the network for a VM interface"),
538 }),
539 ("network.incoming.packets", {
540 'type': _("Nova"),
541 'label': '',
542 'description': _("Number of incoming "
543 "packets for a VM interface"),
544 }),
545 ("network.outgoing.packets", {
546 'type': _("Nova"),
547 'label': '',
548 'description': _("Number of outgoing "
549 "packets for a VM interface"),
550 }),
svavilap022f56f2015-12-04 14:05:39 -0500551 ("network.incoming.bytes.rate", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500552 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500553 'label': '',
554 'description': _("Average rate per sec of incoming "
555 "bytes on a VM network interface"),
556 }),
557 ("network.outgoing.bytes.rate", {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500558 'type': _("Nova"),
svavilap022f56f2015-12-04 14:05:39 -0500559 'label': '',
560 'description': _("Average rate per sec of outgoing "
561 "bytes on a VM network interface"),
562 }),
Srikanth Vavilapalli6ff55982016-01-22 14:35:50 -0500563 ("network.incoming.packets.rate", {
564 'type': _("Nova"),
565 'label': '',
566 'description': _("Average rate per sec of incoming "
567 "packets on a VM network interface"),
568 }),
569 ("network.outgoing.packets.rate", {
570 'type': _("Nova"),
571 'label': '',
572 'description': _("Average rate per sec of outgoing "
573 "packets on a VM network interface"),
574 }),
svavilap022f56f2015-12-04 14:05:39 -0500575 ])
576 # Adding flavor based meters into meters_info dict
577 # TODO(lsmola) this kind of meter will be probably deprecated
578 # https://bugs.launchpad.net/ceilometer/+bug/1208365 . Delete it then.
579 #for flavor in get_flavor_names(self._request):
580 # name = 'instance:%s' % flavor
581 # meters_info[name] = dict(meters_info["instance:<type>"])
582
583 # meters_info[name]['description'] = (
584 # _('Duration of instance type %s (openstack flavor)') %
585 # flavor)
586
587 # TODO(lsmola) allow to set specific in local_settings. For all meters
588 # because users can have their own agents and meters.
589 return meters_info
590
591 def _get_neutron_meters_info(self):
592 """Returns additional info for each meter.
593
594 That will be used for augmenting the Ceilometer meter.
595 """
596
597 # TODO(lsmola) Unless the Ceilometer will provide the information
598 # below, I need to define it as a static here. I will be joining this
599 # to info that I am able to obtain from Ceilometer meters, hopefully
600 # some day it will be supported all.
601 return datastructures.SortedDict([
602 ('network', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500603 'type': _("Neutron"),
svavilap022f56f2015-12-04 14:05:39 -0500604 'label': '',
605 'description': _("Existence of network"),
606 }),
Srikanth Vavilapalli6ff55982016-01-22 14:35:50 -0500607 ('network.create', {
608 'type': _("Neutron"),
609 'label': '',
610 'description': _("Creation requests for this network"),
611 }),
612 ('network.update', {
613 'type': _("Neutron"),
614 'label': '',
615 'description': _("Update requests for this network"),
616 }),
svavilap022f56f2015-12-04 14:05:39 -0500617 ('subnet', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500618 'type': _("Neutron"),
svavilap022f56f2015-12-04 14:05:39 -0500619 'label': '',
620 'description': _("Existence of subnet"),
621 }),
Srikanth Vavilapalli6ff55982016-01-22 14:35:50 -0500622 ('subnet.create', {
623 'type': _("Neutron"),
624 'label': '',
625 'description': _("Creation requests for this subnet"),
626 }),
627 ('subnet.update', {
628 'type': _("Neutron"),
629 'label': '',
630 'description': _("Update requests for this subnet"),
631 }),
svavilap022f56f2015-12-04 14:05:39 -0500632 ('port', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500633 'type': _("Neutron"),
svavilap022f56f2015-12-04 14:05:39 -0500634 'label': '',
635 'description': _("Existence of port"),
636 }),
Srikanth Vavilapalli6ff55982016-01-22 14:35:50 -0500637 ('port.create', {
638 'type': _("Neutron"),
639 'label': '',
640 'description': _("Creation requests for this port"),
641 }),
642 ('port.update', {
643 'type': _("Neutron"),
644 'label': '',
645 'description': _("Update requests for this port"),
646 }),
647 ('router', {
648 'type': _("Neutron"),
649 'label': '',
650 'description': _("Existence of router"),
651 }),
652 ('router.create', {
653 'type': _("Neutron"),
654 'label': '',
655 'description': _("Creation requests for this router"),
656 }),
657 ('router.update', {
658 'type': _("Neutron"),
659 'label': '',
660 'description': _("Update requests for this router"),
661 }),
svavilap022f56f2015-12-04 14:05:39 -0500662 ('ip.floating', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500663 'type': _("Neutron"),
svavilap022f56f2015-12-04 14:05:39 -0500664 'label': '',
665 'description': _("Existence of floating ip"),
666 }),
Srikanth Vavilapalli6ff55982016-01-22 14:35:50 -0500667 ('ip.floating.create', {
668 'type': _("Neutron"),
669 'label': '',
670 'description': _("Creation requests for this floating ip"),
671 }),
672 ('ip.floating.update', {
673 'type': _("Neutron"),
674 'label': '',
675 'description': _("Update requests for this floating ip"),
676 }),
svavilap022f56f2015-12-04 14:05:39 -0500677 ])
678
679 def _get_glance_meters_info(self):
680 """Returns additional info for each meter.
681
682 That will be used for augmenting the Ceilometer meter.
683 """
684
685 # TODO(lsmola) Unless the Ceilometer will provide the information
686 # below, I need to define it as a static here. I will be joining this
687 # to info that I am able to obtain from Ceilometer meters, hopefully
688 # some day it will be supported all.
689 return datastructures.SortedDict([
690 ('image', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500691 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500692 'label': '',
693 'description': _("Image existence check"),
694 }),
695 ('image.size', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500696 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500697 'label': '',
698 'description': _("Uploaded image size"),
699 }),
700 ('image.update', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500701 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500702 'label': '',
703 'description': _("Number of image updates"),
704 }),
705 ('image.upload', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500706 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500707 'label': '',
708 'description': _("Number of image uploads"),
709 }),
710 ('image.delete', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500711 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500712 'label': '',
713 'description': _("Number of image deletions"),
714 }),
715 ('image.download', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500716 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500717 'label': '',
718 'description': _("Image is downloaded"),
719 }),
720 ('image.serve', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500721 'type': _("Glance"),
svavilap022f56f2015-12-04 14:05:39 -0500722 'label': '',
723 'description': _("Image is served out"),
724 }),
725 ])
726
727 def _get_cinder_meters_info(self):
728 """Returns additional info for each meter.
729
730 That will be used for augmenting the Ceilometer meter.
731 """
732
733 # TODO(lsmola) Unless the Ceilometer will provide the information
734 # below, I need to define it as a static here. I will be joining this
735 # to info that I am able to obtain from Ceilometer meters, hopefully
736 # some day it will be supported all.
737 return datastructures.SortedDict([
738 ('volume', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500739 'type': _("Cinder"),
svavilap022f56f2015-12-04 14:05:39 -0500740 'label': '',
741 'description': _("Existence of volume"),
742 }),
743 ('volume.size', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500744 'type': _("Cinder"),
svavilap022f56f2015-12-04 14:05:39 -0500745 'label': '',
746 'description': _("Size of volume"),
747 }),
748 ])
749
750 def _get_swift_meters_info(self):
751 """Returns additional info for each meter.
752
753 That will be used for augmenting the Ceilometer meter.
754 """
755
756 # TODO(lsmola) Unless the Ceilometer will provide the information
757 # below, I need to define it as a static here. I will be joining this
758 # to info that I am able to obtain from Ceilometer meters, hopefully
759 # some day it will be supported all.
760 return datastructures.SortedDict([
761 ('storage.objects', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500762 'type': _("Swift"),
svavilap022f56f2015-12-04 14:05:39 -0500763 'label': '',
764 'description': _("Number of objects"),
765 }),
766 ('storage.objects.size', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500767 'type': _("Swift"),
svavilap022f56f2015-12-04 14:05:39 -0500768 'label': '',
769 'description': _("Total size of stored objects"),
770 }),
771 ('storage.objects.containers', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500772 'type': _("Swift"),
svavilap022f56f2015-12-04 14:05:39 -0500773 'label': '',
774 'description': _("Number of containers"),
775 }),
776 ('storage.objects.incoming.bytes', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500777 'type': _("Swift"),
svavilap022f56f2015-12-04 14:05:39 -0500778 'label': '',
779 'description': _("Number of incoming bytes"),
780 }),
781 ('storage.objects.outgoing.bytes', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500782 'type': _("Swift"),
svavilap022f56f2015-12-04 14:05:39 -0500783 'label': '',
784 'description': _("Number of outgoing bytes"),
785 }),
786 ('storage.api.request', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500787 'type': _("Swift"),
svavilap022f56f2015-12-04 14:05:39 -0500788 'label': '',
789 'description': _("Number of API requests against swift"),
790 }),
791 ])
792
793 def _get_kwapi_meters_info(self):
794 """Returns additional info for each meter.
795
796 That will be used for augmenting the Ceilometer meter.
797 """
798
799 # TODO(lsmola) Unless the Ceilometer will provide the information
800 # below, I need to define it as a static here. I will be joining this
801 # to info that I am able to obtain from Ceilometer meters, hopefully
802 # some day it will be supported all.
803 return datastructures.SortedDict([
804 ('energy', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500805 'type': _("Kwapi"),
svavilap022f56f2015-12-04 14:05:39 -0500806 'label': '',
807 'description': _("Amount of energy"),
808 }),
809 ('power', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500810 'type': _("Kwapi"),
svavilap022f56f2015-12-04 14:05:39 -0500811 'label': '',
812 'description': _("Power consumption"),
813 }),
814 ])
815
816 def _get_ipmi_meters_info(self):
817 """Returns additional info for each meter
818
819 That will be used for augmenting the Ceilometer meter
820 """
821
822 # TODO(lsmola) Unless the Ceilometer will provide the information
823 # below, I need to define it as a static here. I will be joining this
824 # to info that I am able to obtain from Ceilometer meters, hopefully
825 # some day it will be supported all.
826 return datastructures.SortedDict([
827 ('hardware.ipmi.node.power', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500828 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500829 'label': '',
830 'description': _("System Current Power"),
831 }),
832 ('hardware.ipmi.fan', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500833 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500834 'label': '',
835 'description': _("Fan RPM"),
836 }),
837 ('hardware.ipmi.temperature', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500838 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500839 'label': '',
840 'description': _("Sensor Temperature Reading"),
841 }),
842 ('hardware.ipmi.current', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500843 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500844 'label': '',
845 'description': _("Sensor Current Reading"),
846 }),
847 ('hardware.ipmi.voltage', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500848 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500849 'label': '',
850 'description': _("Sensor Voltage Reading"),
851 }),
852 ('hardware.ipmi.node.inlet_temperature', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500853 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500854 'label': '',
855 'description': _("System Inlet Temperature Reading"),
856 }),
857 ('hardware.ipmi.node.outlet_temperature', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500858 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500859 'label': '',
860 'description': _("System Outlet Temperature Reading"),
861 }),
862 ('hardware.ipmi.node.airflow', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500863 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500864 'label': '',
865 'description': _("System Airflow Reading"),
866 }),
867 ('hardware.ipmi.node.cups', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500868 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500869 'label': '',
870 'description': _("System CUPS Reading"),
871 }),
872 ('hardware.ipmi.node.cpu_util', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500873 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500874 'label': '',
875 'description': _("System CPU Utility Reading"),
876 }),
877 ('hardware.ipmi.node.mem_util', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500878 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500879 'label': '',
880 'description': _("System Memory Utility Reading"),
881 }),
882 ('hardware.ipmi.node.io_util', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500883 'type': _("IPMI"),
svavilap022f56f2015-12-04 14:05:39 -0500884 'label': '',
885 'description': _("System IO Utility Reading"),
886 }),
887 ])
888
889 def _get_vcpe_meters_info(self):
890 """Returns additional info for each meter
891
892 That will be used for augmenting the Ceilometer meter
893 """
894
895 # TODO(lsmola) Unless the Ceilometer will provide the information
896 # below, I need to define it as a static here. I will be joining this
897 # to info that I am able to obtain from Ceilometer meters, hopefully
898 # some day it will be supported all.
899 return datastructures.SortedDict([
900 ('vcpe', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500901 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500902 'label': '',
903 'description': _("Existence of vcpe instance"),
904 }),
905 ('vcpe.dns.cache.size', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500906 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500907 'label': '',
908 'description': _("Number of entries in DNS cache"),
909 }),
910 ('vcpe.dns.total_instered_entries', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500911 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500912 'label': '',
913 'description': _("Total number of inserted entries into the cache"),
914 }),
915 ('vcpe.dns.replaced_unexpired_entries', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500916 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500917 'label': '',
918 'description': _("Unexpired entries that were thrown out of cache"),
919 }),
920 ('vcpe.dns.queries_answered_locally', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500921 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500922 'label': '',
923 'description': _("Number of cache hits"),
924 }),
925 ('vcpe.dns.queries_forwarded', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500926 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500927 'label': '',
928 'description': _("Number of cache misses"),
929 }),
930 ('vcpe.dns.server.queries_sent', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500931 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500932 'label': '',
933 'description': _("For each upstream server, the number of queries sent"),
934 }),
935 ('vcpe.dns.server.queries_failed', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500936 'type': _("VCPE"),
svavilap022f56f2015-12-04 14:05:39 -0500937 'label': '',
938 'description': _("For each upstream server, the number of queries failed"),
939 }),
940 ])
941
942 def _get_sdn_meters_info(self):
943 """Returns additional info for each meter
944
945 That will be used for augmenting the Ceilometer meter
946 """
947
948 # TODO(lsmola) Unless the Ceilometer will provide the information
949 # below, I need to define it as a static here. I will be joining this
950 # to info that I am able to obtain from Ceilometer meters, hopefully
951 # some day it will be supported all.
952 return datastructures.SortedDict([
953 ('switch', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500954 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500955 'label': '',
956 'description': _("Existence of switch"),
957 }),
958 ('switch.port', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500959 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500960 'label': '',
961 'description': _("Existence of port"),
962 }),
963 ('switch.port.receive.packets', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500964 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500965 'label': '',
966 'description': _("Packets received on port"),
967 }),
968 ('switch.port.transmit.packets', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500969 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500970 'label': '',
971 'description': _("Packets transmitted on port"),
972 }),
973 ('switch.port.receive.drops', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500974 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500975 'label': '',
976 'description': _("Drops received on port"),
977 }),
978 ('switch.port.transmit.drops', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500979 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500980 'label': '',
981 'description': _("Drops transmitted on port"),
982 }),
983 ('switch.port.receive.errors', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500984 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500985 'label': '',
986 'description': _("Errors received on port"),
987 }),
988 ('switch.port.transmit.errors', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500989 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500990 'label': '',
991 'description': _("Errors transmitted on port"),
992 }),
993 ('switch.flow', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500994 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -0500995 'label': '',
996 'description': _("Duration of flow"),
997 }),
998 ('switch.flow.packets', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -0500999 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -05001000 'label': '',
1001 'description': _("Packets received"),
1002 }),
1003 ('switch.table', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001004 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -05001005 'label': '',
1006 'description': _("Existence of table"),
1007 }),
1008 ('switch.table.active.entries', {
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001009 'type': _("SDN"),
svavilap022f56f2015-12-04 14:05:39 -05001010 'label': '',
1011 'description': _("Active entries in table"),
1012 }),
1013 ])
1014
1015def make_query(user_id=None, tenant_id=None, resource_id=None,
1016 user_ids=None, tenant_ids=None, resource_ids=None):
1017 """Returns query built from given parameters.
1018
1019 This query can be then used for querying resources, meters and
1020 statistics.
1021
1022 :Parameters:
1023 - `user_id`: user_id, has a priority over list of ids
1024 - `tenant_id`: tenant_id, has a priority over list of ids
1025 - `resource_id`: resource_id, has a priority over list of ids
1026 - `user_ids`: list of user_ids
1027 - `tenant_ids`: list of tenant_ids
1028 - `resource_ids`: list of resource_ids
1029 """
1030 user_ids = user_ids or []
1031 tenant_ids = tenant_ids or []
1032 resource_ids = resource_ids or []
1033
1034 query = []
1035 if user_id:
1036 user_ids = [user_id]
1037 for u_id in user_ids:
1038 query.append({"field": "user_id", "op": "eq", "value": u_id})
1039
1040 if tenant_id:
1041 tenant_ids = [tenant_id]
1042 for t_id in tenant_ids:
1043 query.append({"field": "project_id", "op": "eq", "value": t_id})
1044
1045 if resource_id:
1046 resource_ids = [resource_id]
1047 for r_id in resource_ids:
1048 query.append({"field": "resource_id", "op": "eq", "value": r_id})
1049
1050 return query
1051
1052def calc_date_args(date_from, date_to, date_options):
1053 # TODO(lsmola) all timestamps should probably work with
1054 # current timezone. And also show the current timezone in chart.
1055 if date_options == "other":
1056 try:
1057 if date_from:
1058 date_from = pytz.utc.localize(
1059 datetime.datetime.strptime(str(date_from), "%Y-%m-%d"))
1060 else:
1061 # TODO(lsmola) there should be probably the date
1062 # of the first sample as default, so it correctly
1063 # counts the time window. Though I need ordering
1064 # and limit of samples to obtain that.
1065 pass
1066 if date_to:
1067 date_to = pytz.utc.localize(
1068 datetime.datetime.strptime(str(date_to), "%Y-%m-%d"))
1069 # It returns the beginning of the day, I want the end of
1070 # the day, so I add one day without a second.
1071 date_to = (date_to + datetime.timedelta(days=1) -
1072 datetime.timedelta(seconds=1))
1073 else:
1074 date_to = timezone.now()
1075 except Exception:
1076 raise ValueError(_("The dates haven't been recognized"))
1077 else:
1078 try:
1079 date_to = timezone.now()
1080 date_from = date_to - datetime.timedelta(days=float(date_options))
1081 except Exception as e:
1082 raise e
1083 #raise ValueError(_("The time delta must be a number representing "
1084 # "the time span in days"))
1085 return date_from, date_to
1086
1087class MetersList(APIView):
1088 method_kind = "list"
1089 method_name = "meters"
1090
1091 def get(self, request, format=None):
1092 if (not request.user.is_authenticated()):
1093 raise PermissionDenied("You must be authenticated in order to use this API")
1094 tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
1095 if (not tenant_ceilometer_url):
1096 raise XOSMissingField("Tenant ceilometer URL is missing")
1097 tenant_map = getTenantControllerTenantMap(request.user)
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001098 resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url)
1099 meters = Meters(request, ceilometer_url=tenant_ceilometer_url, tenant_map=tenant_map, resource_map=resource_map)
svavilap022f56f2015-12-04 14:05:39 -05001100 services = {
1101 _('Nova'): meters.list_nova(),
1102 _('Neutron'): meters.list_neutron(),
1103 _('VCPE'): meters.list_vcpe(),
1104 _('SDN'): meters.list_sdn(),
1105 }
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001106 meters = []
1107 for service,smeters in services.iteritems():
1108 meters.extend(smeters)
1109 return Response(meters)
svavilap022f56f2015-12-04 14:05:39 -05001110
1111class MeterStatisticsList(APIView):
1112 method_kind = "list"
1113 method_name = "meterstatistics"
1114
1115 def get(self, request, format=None):
1116 if (not request.user.is_authenticated()):
1117 raise PermissionDenied("You must be authenticated in order to use this API")
1118 tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
1119 if (not tenant_ceilometer_url):
1120 raise XOSMissingField("Tenant ceilometer URL is missing")
1121 tenant_map = getTenantControllerTenantMap(request.user)
1122
1123 date_options = request.QUERY_PARAMS.get('period', 1)
1124 date_from = request.QUERY_PARAMS.get('date_from', '')
1125 date_to = request.QUERY_PARAMS.get('date_to', '')
1126
1127 try:
1128 date_from, date_to = calc_date_args(date_from,
1129 date_to,
1130 date_options)
1131 except Exception as e:
1132 raise e
1133
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001134 additional_query = []
1135 if date_from:
1136 additional_query.append({'field': 'timestamp',
1137 'op': 'ge',
1138 'value': date_from})
1139 if date_to:
1140 additional_query.append({'field': 'timestamp',
1141 'op': 'le',
1142 'value': date_to})
1143
1144 meter_name = request.QUERY_PARAMS.get('meter', None)
1145 tenant_id = request.QUERY_PARAMS.get('tenant', None)
1146 resource_id = request.QUERY_PARAMS.get('resource', None)
1147
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -05001148 query = []
1149 if tenant_id:
1150 query.extend(make_query(tenant_id=tenant_id))
1151 if resource_id:
1152 query.extend(make_query(resource_id=resource_id))
1153
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001154 if meter_name:
1155 #Statistics query for one meter
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001156 if additional_query:
1157 query = query + additional_query
1158 statistics = statistic_list(request, meter_name,
1159 ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
1160 statistic = statistics[-1]
1161 row = {"name": 'none',
1162 "meter": meter_name,
1163 "time": statistic["period_end"],
1164 "value": statistic["avg"]}
1165 return Response(row)
1166
1167 #Statistics query for all meter
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001168 resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url)
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -05001169 meters = Meters(request, ceilometer_url=tenant_ceilometer_url, query=query, tenant_map=tenant_map, resource_map=resource_map)
svavilap022f56f2015-12-04 14:05:39 -05001170 services = {
1171 _('Nova'): meters.list_nova(),
1172 _('Neutron'): meters.list_neutron(),
1173 _('VCPE'): meters.list_vcpe(),
1174 _('SDN'): meters.list_sdn(),
1175 }
1176 report_rows = []
1177 for service,meters in services.items():
1178 for meter in meters:
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001179 query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
1180 if additional_query:
1181 query = query + additional_query
svavilap022f56f2015-12-04 14:05:39 -05001182 statistics = statistic_list(request, meter["name"],
1183 ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
Srikanth Vavilapalli80425702015-12-04 17:56:53 -05001184 if not statistics:
1185 continue
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001186 statistic = statistics[-1]
svavilap022f56f2015-12-04 14:05:39 -05001187 row = {"name": 'none',
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001188 "slice": meter["slice"],
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001189 "project_id": meter["project_id"],
Srikanth Vavilapalli0bc65b32015-12-08 19:06:22 -05001190 "service": meter["service"],
1191 "resource_id": meter["resource_id"],
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001192 "resource_name": meter["resource_name"],
svavilap022f56f2015-12-04 14:05:39 -05001193 "meter": meter["name"],
1194 "description": meter["description"],
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001195 "category": service,
svavilap022f56f2015-12-04 14:05:39 -05001196 "time": statistic["period_end"],
1197 "value": statistic["avg"],
1198 "unit": meter["unit"]}
1199 report_rows.append(row)
1200
1201 return Response(report_rows)
1202
1203
1204class MeterSamplesList(APIView):
1205 method_kind = "list"
1206 method_name = "metersamples"
1207
1208 def get(self, request, format=None):
1209 if (not request.user.is_authenticated()):
1210 raise PermissionDenied("You must be authenticated in order to use this API")
1211 tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
1212 if (not tenant_ceilometer_url):
1213 raise XOSMissingField("Tenant ceilometer URL is missing")
1214 meter_name = request.QUERY_PARAMS.get('meter', None)
svavilap022f56f2015-12-04 14:05:39 -05001215 if not meter_name:
1216 raise XOSMissingField("Meter name in query params is missing")
Srikanth Vavilapalli80425702015-12-04 17:56:53 -05001217 limit = request.QUERY_PARAMS.get('limit', 10)
1218 tenant_id = request.QUERY_PARAMS.get('tenant', None)
1219 resource_id = request.QUERY_PARAMS.get('resource', None)
svavilap022f56f2015-12-04 14:05:39 -05001220 query = []
1221 if tenant_id:
Srikanth Vavilapalli80425702015-12-04 17:56:53 -05001222 query.extend(make_query(tenant_id=tenant_id))
1223 if resource_id:
1224 query.extend(make_query(resource_id=resource_id))
svavilap022f56f2015-12-04 14:05:39 -05001225 query.append({"field": "meter", "op": "eq", "value": meter_name})
1226 samples = sample_list(request, meter_name,
Srikanth Vavilapalli80425702015-12-04 17:56:53 -05001227 ceilometer_url=tenant_ceilometer_url, query=query, limit=limit)
Srikanth Vavilapalli73afe292015-12-14 17:35:04 -05001228 if samples:
1229 tenant_map = getTenantControllerTenantMap(request.user)
1230 resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url)
1231 for sample in samples:
1232 if sample["project_id"] in tenant_map.keys():
1233 sample["slice"] = tenant_map[sample["project_id"]]["slice"]
1234 else:
1235 sample["slice"] = sample["project_id"]
1236 if sample["resource_id"] in resource_map.keys():
1237 sample["resource_name"] = resource_map[sample["resource_id"]]
1238 else:
1239 sample["resource_name"] = sample["resource_id"]
svavilap022f56f2015-12-04 14:05:39 -05001240 return Response(samples)
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001241
Srikanth Vavilapalli2b2099c2016-02-01 18:01:56 -05001242class XOSInstanceStatisticsList(APIView):
1243 method_kind = "list"
1244 method_name = "xos-instance-statistics"
1245
1246 def get(self, request, format=None):
1247 if (not request.user.is_authenticated()):
1248 raise PermissionDenied("You must be authenticated in order to use this API")
1249 tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
1250 if (not tenant_ceilometer_url):
1251 raise XOSMissingField("Tenant ceilometer URL is missing")
1252 instance_uuid = request.QUERY_PARAMS.get('instance-uuid', None)
1253 if not instance_uuid:
1254 raise XOSMissingField("Instance UUID in query params is missing")
1255 if not Instance.objects.filter(instance_uuid=instance_uuid):
1256 raise XOSMissingField("XOS Instance object is missing for this uuid")
1257 xos_instance = Instance.objects.filter(instance_uuid=instance_uuid)[0]
1258 tenant_map = getTenantControllerTenantMap(request.user, xos_instance.slice)
1259 tenant_id = tenant_map.keys()[0]
1260 resource_ids = []
1261 resource_ids.append(instance_uuid)
1262 for p in xos_instance.ports.all():
1263 #neutron port resource id is represented in ceilometer as "nova instance-name"+"-"+"nova instance-id"+"-"+"tap"+first 11 characters of port-id
1264 resource_ids.append(xos_instance.instance_id+"-"+instance_uuid+"-tap"+p.port_id[:11])
1265
1266 date_options = request.QUERY_PARAMS.get('period', 1)
1267 date_from = request.QUERY_PARAMS.get('date_from', '')
1268 date_to = request.QUERY_PARAMS.get('date_to', '')
1269
1270 try:
1271 date_from, date_to = calc_date_args(date_from,
1272 date_to,
1273 date_options)
1274 except Exception as e:
1275 raise e
1276
1277 additional_query = []
1278 if date_from:
1279 additional_query.append({'field': 'timestamp',
1280 'op': 'ge',
1281 'value': date_from})
1282 if date_to:
1283 additional_query.append({'field': 'timestamp',
1284 'op': 'le',
1285 'value': date_to})
1286
1287 report_rows = []
1288 for resource_id in resource_ids:
1289 query = []
1290 if tenant_id:
1291 query.extend(make_query(tenant_id=tenant_id))
1292 if resource_id:
1293 query.extend(make_query(resource_id=resource_id))
1294
1295 #Statistics query for all meter
1296 resource_map = get_resource_map(request, ceilometer_url=tenant_ceilometer_url, query=query)
1297 meters = Meters(request, ceilometer_url=tenant_ceilometer_url, query=query, tenant_map=tenant_map, resource_map=resource_map)
1298 services = {
1299 _('Nova'): meters.list_nova(),
1300 _('Neutron'): meters.list_neutron(),
1301 _('VCPE'): meters.list_vcpe(),
1302 _('SDN'): meters.list_sdn(),
1303 }
1304 for service,meters in services.items():
1305 for meter in meters:
1306 query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
1307 if additional_query:
1308 query = query + additional_query
1309 statistics = statistic_list(request, meter["name"],
1310 ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
1311 if not statistics:
1312 continue
1313 statistic = statistics[-1]
1314 row = {"name": 'none',
1315 "slice": meter["slice"],
1316 "project_id": meter["project_id"],
1317 "service": meter["service"],
1318 "resource_id": meter["resource_id"],
1319 "resource_name": meter["resource_name"],
1320 "meter": meter["name"],
1321 "description": meter["description"],
1322 "category": service,
1323 "time": statistic["period_end"],
1324 "value": statistic["avg"],
1325 "unit": meter["unit"]}
1326 report_rows.append(row)
1327
1328 return Response(report_rows)
1329
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001330class ServiceAdjustScale(APIView):
1331 method_kind = "list"
1332 method_name = "serviceadjustscale"
1333
1334 def get(self, request, format=None):
Srikanth Vavilapalli73afe292015-12-14 17:35:04 -05001335 if (not request.user.is_authenticated()) or (not request.user.is_admin):
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001336 raise PermissionDenied("You must be authenticated admin user in order to use this API")
1337 service = request.QUERY_PARAMS.get('service', None)
1338 slice_hint = request.QUERY_PARAMS.get('slice_hint', None)
1339 scale = request.QUERY_PARAMS.get('scale', None)
1340 if not service or not slice_hint or not scale:
1341 raise XOSMissingField("Mandatory fields missing")
1342 services = Service.select_by_user(request.user)
1343 logger.info('SRIKANTH: Services for this user %(services)s' % {'services':services})
1344 if not services or (not services.get(name=service)):
1345 raise XOSMissingField("Service not found")
1346 service = services.get(name=service)
Srikanth Vavilapalli73afe292015-12-14 17:35:04 -05001347 service.adjust_scale(slice_hint, int(scale))
Srikanth Vavilapalli1ea11fc2015-12-14 00:52:57 -05001348 return Response("Success")