Files
ms 2c1c48df0c
PostgreSQL integration / tests (push) Has been cancelled
init
2026-11-09 13:15:48 +01:00

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)