111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from django.db import models
|
||
|
|
|
||
|
|
|
||
|
|
class TimestampedModel(models.Model):
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
updated_at = models.DateTimeField(auto_now=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
abstract = True
|
||
|
|
|
||
|
|
|
||
|
|
class GlobalConfig(TimestampedModel):
|
||
|
|
name = models.CharField(max_length=64, default="default", unique=True)
|
||
|
|
backup_root = models.CharField(max_length=512)
|
||
|
|
pobsync_home = models.CharField(max_length=512, default="/opt/pobsync")
|
||
|
|
data = models.JSONField(default=dict, blank=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
verbose_name = "global config"
|
||
|
|
verbose_name_plural = "global configs"
|
||
|
|
|
||
|
|
def __str__(self) -> str:
|
||
|
|
return self.name
|
||
|
|
|
||
|
|
|
||
|
|
class HostConfig(TimestampedModel):
|
||
|
|
host = models.CharField(max_length=255, unique=True)
|
||
|
|
address = models.CharField(max_length=255)
|
||
|
|
enabled = models.BooleanField(default=True)
|
||
|
|
config = models.JSONField(default=dict, blank=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
ordering = ["host"]
|
||
|
|
|
||
|
|
def __str__(self) -> str:
|
||
|
|
return self.host
|
||
|
|
|
||
|
|
|
||
|
|
class BackupRun(models.Model):
|
||
|
|
class RunType(models.TextChoices):
|
||
|
|
SCHEDULED = "scheduled", "Scheduled"
|
||
|
|
MANUAL = "manual", "Manual"
|
||
|
|
|
||
|
|
class Status(models.TextChoices):
|
||
|
|
QUEUED = "queued", "Queued"
|
||
|
|
RUNNING = "running", "Running"
|
||
|
|
SUCCESS = "success", "Success"
|
||
|
|
FAILED = "failed", "Failed"
|
||
|
|
CANCELLED = "cancelled", "Cancelled"
|
||
|
|
|
||
|
|
host = models.ForeignKey(HostConfig, on_delete=models.PROTECT, related_name="runs")
|
||
|
|
run_type = models.CharField(max_length=16, choices=RunType.choices, default=RunType.SCHEDULED)
|
||
|
|
status = models.CharField(max_length=16, choices=Status.choices, default=Status.QUEUED)
|
||
|
|
started_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
ended_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
snapshot_path = models.CharField(max_length=1024, blank=True)
|
||
|
|
base_path = models.CharField(max_length=1024, blank=True)
|
||
|
|
rsync_exit_code = models.IntegerField(null=True, blank=True)
|
||
|
|
result = models.JSONField(default=dict, blank=True)
|
||
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
ordering = ["-created_at"]
|
||
|
|
|
||
|
|
def __str__(self) -> str:
|
||
|
|
return f"{self.host} {self.run_type} {self.status}"
|
||
|
|
|
||
|
|
|
||
|
|
class SnapshotRecord(models.Model):
|
||
|
|
class Kind(models.TextChoices):
|
||
|
|
SCHEDULED = "scheduled", "Scheduled"
|
||
|
|
MANUAL = "manual", "Manual"
|
||
|
|
INCOMPLETE = "incomplete", "Incomplete"
|
||
|
|
|
||
|
|
host = models.ForeignKey(HostConfig, on_delete=models.CASCADE, related_name="snapshots")
|
||
|
|
kind = models.CharField(max_length=16, choices=Kind.choices)
|
||
|
|
dirname = models.CharField(max_length=255)
|
||
|
|
path = models.CharField(max_length=1024)
|
||
|
|
status = models.CharField(max_length=32, blank=True)
|
||
|
|
started_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
ended_at = models.DateTimeField(null=True, blank=True)
|
||
|
|
metadata = models.JSONField(default=dict, blank=True)
|
||
|
|
discovered_at = models.DateTimeField(auto_now_add=True)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
constraints = [
|
||
|
|
models.UniqueConstraint(fields=["host", "kind", "dirname"], name="unique_snapshot_per_host_kind"),
|
||
|
|
]
|
||
|
|
ordering = ["host__host", "-started_at", "dirname"]
|
||
|
|
|
||
|
|
def __str__(self) -> str:
|
||
|
|
return f"{self.host}/{self.kind}/{self.dirname}"
|
||
|
|
|
||
|
|
|
||
|
|
class ScheduleConfig(TimestampedModel):
|
||
|
|
host = models.OneToOneField(HostConfig, on_delete=models.CASCADE, related_name="schedule")
|
||
|
|
cron_expr = models.CharField(max_length=128)
|
||
|
|
user = models.CharField(max_length=64, default="root")
|
||
|
|
enabled = models.BooleanField(default=True)
|
||
|
|
prune = models.BooleanField(default=False)
|
||
|
|
prune_max_delete = models.PositiveIntegerField(default=10)
|
||
|
|
prune_protect_bases = models.BooleanField(default=False)
|
||
|
|
|
||
|
|
class Meta:
|
||
|
|
ordering = ["host__host"]
|
||
|
|
|
||
|
|
def __str__(self) -> str:
|
||
|
|
return f"{self.host} {self.cron_expr}"
|