57 lines
3.5 KiB
Python
57 lines
3.5 KiB
Python
import math
|
|
from datetime import timedelta
|
|
from django.utils import timezone
|
|
from rest_framework import serializers
|
|
KINDS=['metric','flower-status','collector-status','worker-online','worker-offline','worker-heartbeat','task-sent','task-received','task-started','task-succeeded','task-failed','task-retried','task-revoked','task-rejected']
|
|
class MetricPayload(serializers.Serializer):
|
|
cpu=serializers.FloatField(min_value=0,max_value=100)
|
|
ram=serializers.FloatField(min_value=0,max_value=100)
|
|
disk=serializers.FloatField(min_value=0,max_value=100)
|
|
boot_id=serializers.CharField(max_length=100,required=False)
|
|
services=serializers.DictField(child=serializers.BooleanField(),required=False)
|
|
outbox=serializers.IntegerField(min_value=0,required=False)
|
|
class WorkerPayload(serializers.Serializer):
|
|
hostname=serializers.CharField(max_length=255)
|
|
active=serializers.IntegerField(min_value=0,required=False,default=0)
|
|
processed=serializers.IntegerField(min_value=0,required=False,default=0)
|
|
class TaskPayload(serializers.Serializer):
|
|
uuid=serializers.CharField(max_length=200)
|
|
name=serializers.CharField(max_length=255,required=False,allow_blank=True)
|
|
hostname=serializers.CharField(max_length=255,required=False,allow_blank=True)
|
|
runtime=serializers.FloatField(min_value=0,required=False,allow_null=True)
|
|
retries=serializers.IntegerField(min_value=0,required=False,default=0)
|
|
class StatusPayload(serializers.Serializer):
|
|
online=serializers.BooleanField()
|
|
checked_at=serializers.DateTimeField(required=False)
|
|
class Envelope(serializers.Serializer):
|
|
id=serializers.UUIDField()
|
|
kind=serializers.ChoiceField(choices=KINDS)
|
|
occurred_at=serializers.DateTimeField()
|
|
payload=serializers.DictField()
|
|
def validate(self,data):
|
|
if data['occurred_at']>timezone.now()+timedelta(minutes=5):
|
|
raise serializers.ValidationError('Zeitstempel liegt zu weit in der Zukunft')
|
|
cls=MetricPayload if data['kind']=='metric' else WorkerPayload if data['kind'].startswith('worker-') else TaskPayload if data['kind'].startswith('task-') else StatusPayload
|
|
s=cls(data=data['payload']); s.is_valid(raise_exception=True)
|
|
for field in ('cpu','ram','disk','runtime'):
|
|
value=s.validated_data.get(field)
|
|
if value is not None and not math.isfinite(value):
|
|
raise serializers.ValidationError('Messwerte müssen endlich sein')
|
|
services=s.validated_data.get('services',{})
|
|
if len(services)>20 or any(len(k)>50 for k in services):
|
|
raise serializers.ValidationError('Maximal 20 Dienste mit Namen bis 50 Zeichen')
|
|
# Use normalized validated values, never the original loosely typed input.
|
|
normalized=dict(s.data)
|
|
if any(isinstance(v,float) and not math.isfinite(v) for v in normalized.values()):
|
|
raise serializers.ValidationError('Messwerte müssen endlich sein')
|
|
data['payload']={key:value for key,value in normalized.items() if key in data['payload']}
|
|
return data
|
|
class Batch(serializers.Serializer):
|
|
events=Envelope(many=True,allow_empty=False,max_length=500)
|
|
class ConfigurationSerializer(serializers.Serializer):
|
|
retention_days=serializers.IntegerField(min_value=7,max_value=3650)
|
|
heartbeat_timeout=serializers.IntegerField(min_value=30,max_value=3600)
|
|
cpu_warning=serializers.IntegerField(min_value=1,max_value=100)
|
|
ram_warning=serializers.IntegerField(min_value=1,max_value=100)
|
|
disk_warning=serializers.IntegerField(min_value=1,max_value=100)
|