1818from pytz .exceptions import UnknownTimeZoneError
1919from rest_framework import serializers , status
2020from rest_framework .generics import GenericAPIView
21+ from rest_framework .permissions import BasePermission
2122from rest_framework .response import Response
2223from swapper import load_model
2324
3637
3738logger = logging .getLogger (__name__ )
3839Chart = load_model ('monitoring' , 'Chart' )
40+ Check = load_model ('check' , 'Check' )
3941Metric = load_model ('monitoring' , 'Metric' )
4042AlertSettings = load_model ('monitoring' , 'AlertSettings' )
4143Device = load_model ('config' , 'Device' )
4446Location = load_model ('geo' , 'Location' )
4547
4648
47- class DevicePermission (BasePermission ):
49+ class DevicePermission (BasePermission ): # noqa
4850 def has_object_permission (self , request , view , obj ):
4951 return request .query_params .get ('key' ) == obj .key
5052
5153
5254class MetricChartsMixin :
53- def _write (self , pk , data = None ):
55+ def _write (self , pk , time = None , current = False ):
5456 """
5557 write metrics to database
5658 """
57- if data is None :
58- # saves raw device data
59+ # If object not of type check ie. It is DeviceData
60+ if not hasattr ( self , 'check_instance' ):
5961 self .instance .save_data ()
6062 data = self .instance .data
63+ device_extra_tags = self ._get_extra_tags (self .instance )
64+ # Get data attribute from DeviceData object
65+ else :
66+ devicedata_instance = DeviceData .objects .get (pk = pk )
67+ data = getattr (devicedata_instance , 'data' , {})
68+ device_extra_tags = self ._get_extra_tags (devicedata_instance )
69+
6170 ct = ContentType .objects .get_for_model (Device )
62- device_extra_tags = self ._get_extra_tags (self .instance )
6371 for interface in data .get ('interfaces' , []):
6472 ifname = interface ['name' ]
6573 extra_tags = Metric ._sort_dict (device_extra_tags )
@@ -358,13 +366,19 @@ def _create_access_tech_chart(self, metric):
358366 chart .full_clean ()
359367 chart .save ()
360368
361- def _init_previous_data (self , data = None ):
369+ def _init_previous_data (self ):
362370 """
363371 makes NetJSON interfaces of previous
364372 snapshots more easy to access
365373 """
366- if data is None :
374+
375+ # If object not of type check
376+ if not hasattr (self , 'check_instance' ):
367377 data = self .instance .data or {}
378+ # Get data attribute from Device object
379+ else :
380+ data = getattr (self .related_object , 'data' , {})
381+
368382 if data :
369383 data = deepcopy (data )
370384 data ['interfaces_dict' ] = {}
@@ -375,7 +389,7 @@ def _init_previous_data(self, data=None):
375389
376390class DeviceMetricView (GenericAPIView , MetricChartsMixin ):
377391 model = DeviceData
378- queryset = DeviceData .objects .all ()
392+ queryset = DeviceData .objects .select_related ( 'devicelocation' ). all ()
379393 serializer_class = serializers .Serializer
380394 permission_classes = [DevicePermission ]
381395 schema = schema
@@ -421,13 +435,21 @@ def _get_charts_data(self, charts, time, timezone):
421435 # prepare chart dict
422436 try :
423437 chart_dict = chart .read (time = time , x_axys = x_axys , timezone = timezone )
438+ if not chart_dict ['traces' ]:
439+ continue
424440 chart_dict ['description' ] = chart .description
425- chart_dict ['title' ] = chart .title .format (metric = chart .metric )
441+ chart_dict ['title' ] = chart .title .format (
442+ metric = chart .metric , ** chart .metric .tags
443+ )
426444 chart_dict ['type' ] = chart .type
427445 chart_dict ['unit' ] = chart .unit
428446 chart_dict ['summary_labels' ] = chart .summary_labels
429447 chart_dict ['colors' ] = chart .colors
430448 chart_dict ['colorscale' ] = chart .colorscale
449+ for attr in ['fill' , 'xaxis' , 'yaxis' ]:
450+ value = getattr (chart , attr )
451+ if value :
452+ chart_dict [attr ] = value
431453 except InvalidChartConfigException :
432454 logger .exception (f'Skipped chart for metric { chart .metric } ' )
433455 continue
@@ -492,14 +514,28 @@ def post(self, request, pk):
492514 except ValidationError as e :
493515 logger .info (e .message )
494516 return Response (e .message , status = status .HTTP_400_BAD_REQUEST )
517+ time_obj = request .query_params .get (
518+ 'time' , now ().utcnow ().strftime ('%d-%m-%Y_%H:%M:%S.%f' )
519+ )
520+ current = request .query_params .get ('current' , False )
521+ try :
522+ time = datetime .strptime (time_obj , '%d-%m-%Y_%H:%M:%S.%f' ).replace (
523+ tzinfo = UTC
524+ )
525+ except ValueError :
526+ return Response ({'detail' : _ ('Incorrect time format' )}, status = 400 )
495527 try :
496528 # write data
497- self ._write (self .instance .pk )
529+ self ._write (self .instance .pk , time = time )
498530 except ValidationError as e :
499531 logger .info (e .message_dict )
500532 return Response (e .message_dict , status = status .HTTP_400_BAD_REQUEST )
501533 device_metrics_received .send (
502- sender = self .model , instance = self .instance , request = request
534+ sender = self .model ,
535+ instance = self .instance ,
536+ request = request ,
537+ time = time ,
538+ current = current ,
503539 )
504540 return Response (None )
505541
0 commit comments