import uuid from django.conf import settings from django.db import models from django.db.models import Q class Segment(models.Model): name=models.CharField(max_length=100,unique=True) cidr=models.CharField(max_length=100,blank=True) def __str__(self): return self.name class Server(models.Model): id=models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False) name=models.CharField(max_length=150,unique=True) segment=models.ForeignKey(Segment,on_delete=models.PROTECT) address=models.CharField(max_length=255,blank=True) enabled=models.BooleanField(default=True) maintenance=models.BooleanField(default=False) last_seen=models.DateTimeField(null=True,blank=True) latest_sample_at=models.DateTimeField(null=True,blank=True) latest=models.JSONField(default=dict,blank=True) created_at=models.DateTimeField(auto_now_add=True) def __str__(self): return self.name class AgentCredential(models.Model): server=models.ForeignKey(Server,on_delete=models.CASCADE) digest=models.CharField(max_length=64,unique=True) label=models.CharField(max_length=100,default='agent') active=models.BooleanField(default=True) created_at=models.DateTimeField(auto_now_add=True) class AccessToken(models.Model): user=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE) digest=models.CharField(max_length=64,unique=True) expires_at=models.DateTimeField(db_index=True) class Event(models.Model): id=models.UUIDField(primary_key=True) server=models.ForeignKey(Server,on_delete=models.CASCADE) kind=models.CharField(max_length=50,db_index=True) occurred_at=models.DateTimeField(db_index=True) received_at=models.DateTimeField(auto_now_add=True,db_index=True) payload=models.JSONField(default=dict) class Meta: indexes=[models.Index(fields=['server','occurred_at']),models.Index(fields=['server','kind','occurred_at'])] class Metric(models.Model): event=models.OneToOneField(Event,on_delete=models.CASCADE,primary_key=True) server=models.ForeignKey(Server,on_delete=models.CASCADE) at=models.DateTimeField(db_index=True) cpu=models.FloatField() ram=models.FloatField() disk=models.FloatField() class Meta: indexes=[models.Index(fields=['server','at'])] class Worker(models.Model): server=models.ForeignKey(Server,on_delete=models.CASCADE) hostname=models.CharField(max_length=255) last_seen=models.DateTimeField() online=models.BooleanField(default=True) active=models.IntegerField(default=0) processed=models.BigIntegerField(default=0) class Meta: constraints=[models.UniqueConstraint(fields=['server','hostname'],name='unique_worker_per_collector')] class Task(models.Model): server=models.ForeignKey(Server,on_delete=models.CASCADE) task_id=models.CharField(max_length=200) name=models.CharField(max_length=255,blank=True) worker=models.CharField(max_length=255,blank=True) state=models.CharField(max_length=30) first_at=models.DateTimeField() last_at=models.DateTimeField(db_index=True) runtime=models.FloatField(null=True,blank=True) retries=models.IntegerField(default=0) class Meta: constraints=[models.UniqueConstraint(fields=['server','task_id'],name='unique_task_per_collector')] indexes=[models.Index(fields=['server','last_at'])] class Alarm(models.Model): server=models.ForeignKey(Server,on_delete=models.CASCADE) code=models.CharField(max_length=80) severity=models.CharField(max_length=20,default='warning') message=models.CharField(max_length=400) opened_at=models.DateTimeField(auto_now_add=True) resolved_at=models.DateTimeField(null=True,blank=True) acknowledged_at=models.DateTimeField(null=True,blank=True) acknowledged_by=models.ForeignKey(settings.AUTH_USER_MODEL,null=True,blank=True,on_delete=models.SET_NULL) class Meta: constraints=[models.UniqueConstraint(fields=['server','code'],condition=Q(resolved_at__isnull=True),name='one_open_alarm')] class Notification(models.Model): alarm=models.OneToOneField(Alarm,on_delete=models.CASCADE) sent_at=models.DateTimeField(null=True,blank=True) attempts=models.IntegerField(default=0) next_attempt=models.DateTimeField() last_error=models.CharField(max_length=100,blank=True) class Configuration(models.Model): id=models.PositiveSmallIntegerField(primary_key=True,default=1,editable=False) retention_days=models.PositiveIntegerField(default=90) heartbeat_timeout=models.PositiveIntegerField(default=60) cpu_warning=models.PositiveIntegerField(default=85) ram_warning=models.PositiveIntegerField(default=90) disk_warning=models.PositiveIntegerField(default=90) updated_at=models.DateTimeField(auto_now=True) class Audit(models.Model): at=models.DateTimeField(auto_now_add=True) actor=models.CharField(max_length=150) action=models.CharField(max_length=200) details=models.JSONField(default=dict)