Release / verify (push) Canceled after 0s
CI / checks (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 0s
Release / test (push) Canceled after 0s
Release / publish (backend) (push) Canceled after 0s
Release / publish (frontend) (push) Canceled after 0s
Release / publish (proxy) (push) Canceled after 0s
Release / publish (updater) (push) Canceled after 0s
Geplante Wartung: Fehler zeigen sich sofort statt erst um 3 Uhr nachts, und der Master lässt sich unbeaufsichtigt aktualisieren. Auf einem Test-Cluster live geprüft (Neustart und ein echtes Update mit Umschaltung), siehe Handbuch „Geplante Wartung“. - **Rollenprüfung beim Einplanen:** Ein Host, der in einem Cluster gerade CARP-MASTER ist, lässt sich nicht mehr einplanen (Neustart/Update/Major-Upgrade). Bisher wurde der Plan angenommen und scheiterte erst zur Uhrzeit. Der Planungsdialog zeigt den Grund an und sperrt den Button. Ist die Rolle nicht feststellbar (Host gerade nicht erreichbar), wird weiter angenommen; die volle Prüfung läuft wie bisher zum Zündzeitpunkt. - **Benachrichtigung „Geplante Wartung nicht ausgeführt“:** Eine fehlgeschlagene geplante Wartung meldet sich per Webhook/E-Mail (einzeln schaltbar in den Einstellungen, standardmäßig an). Offen für drei Tage nach dem geplanten Zeitpunkt, dann ohne „behoben“-Meldung geschlossen. Neue Spalte `notification_settings.scheduled_maintenance_failed_enabled` (Migration `0006`). - **Automatische CARP-Umschaltung (Option pro Plan, standardmäßig aus):** Ein geplanter Neustart, Update oder Major-Upgrade auf dem MASTER schaltet vorher auf den Partner um, prüft die Übernahme, führt die Aktion aus, wartet auf die Rückkehr des Hosts und schaltet zurück. Fehler vor dem Start der Aktion stellen den Normalbetrieb wieder her; danach bleibt der Host bewusst im Wartungsmodus (Partner trägt den Verkehr) und es kommt eine Benachrichtigung. Der Ablauf steht in der Datenbank und überlebt einen Neustart des Backends. Neue Spalten an `scheduled_maintenance` (Migration `0007`). - **Backup vor geplantem Update:** Ein geplantes Update oder Major-Upgrade zieht unmittelbar vor dem Start selbst ein Konfigurationsbackup (nur lesend auf der Firewall). Bisher scheiterte jeder Plan, der mehr als 24 Stunden in der Zukunft lag, an der Backup-Aktualität. Schlägt das Backup fehl, wird nicht aktualisiert.
102 lines
3.4 KiB
Python
102 lines
3.4 KiB
Python
import uuid
|
|
from datetime import datetime
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
from app.config import settings
|
|
|
|
SmtpSecurity = Literal["none", "starttls", "ssl"]
|
|
ProblemType = Literal[
|
|
"host_offline", "cert_expiry", "rule_drift", "revert_failed", "maintenance_unknown",
|
|
"carp_split_brain", "nat_drift", "carp_auto_revert_failed", "network_drift",
|
|
"scheduled_maintenance_failed",
|
|
]
|
|
|
|
|
|
class NotificationSettingsRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
webhook_enabled: bool
|
|
webhook_url: str | None
|
|
webhook_signing_secret_set: bool
|
|
|
|
email_enabled: bool
|
|
smtp_host: str | None
|
|
smtp_port: int
|
|
smtp_security: SmtpSecurity
|
|
smtp_username: str | None
|
|
smtp_password_set: bool
|
|
smtp_from_address: str | None
|
|
smtp_to_addresses: list[str]
|
|
|
|
host_offline_enabled: bool
|
|
cert_expiring_enabled: bool
|
|
rule_drift_enabled: bool
|
|
revert_failed_enabled: bool
|
|
maintenance_unknown_enabled: bool
|
|
carp_health_enabled: bool
|
|
nat_drift_enabled: bool
|
|
network_drift_enabled: bool = True
|
|
carp_auto_revert_failed_enabled: bool
|
|
scheduled_maintenance_failed_enabled: bool = True
|
|
|
|
poll_interval_seconds: int
|
|
updated_at: datetime
|
|
|
|
|
|
class NotificationSettingsUpdate(BaseModel):
|
|
"""Partial update — everything optional, only provided fields change.
|
|
Secret values (smtp_password/webhook_signing_secret) are write-only:
|
|
provide a new value to set it, or the matching clear_* flag to remove
|
|
it — omitting both leaves the currently stored secret untouched, same
|
|
disambiguation pattern as HostUpdate.clear_cluster_name."""
|
|
|
|
webhook_enabled: bool | None = None
|
|
webhook_url: str | None = Field(default=None, max_length=500)
|
|
webhook_signing_secret: str | None = Field(default=None, min_length=1)
|
|
clear_webhook_signing_secret: bool = False
|
|
|
|
email_enabled: bool | None = None
|
|
smtp_host: str | None = Field(default=None, max_length=255)
|
|
smtp_port: int | None = Field(default=None, ge=1, le=65535)
|
|
smtp_security: SmtpSecurity | None = None
|
|
smtp_username: str | None = Field(default=None, max_length=255)
|
|
smtp_password: str | None = Field(default=None, min_length=1)
|
|
clear_smtp_password: bool = False
|
|
smtp_from_address: str | None = Field(default=None, max_length=255)
|
|
smtp_to_addresses: list[str] | None = None
|
|
|
|
host_offline_enabled: bool | None = None
|
|
cert_expiring_enabled: bool | None = None
|
|
rule_drift_enabled: bool | None = None
|
|
revert_failed_enabled: bool | None = None
|
|
maintenance_unknown_enabled: bool | None = None
|
|
carp_health_enabled: bool | None = None
|
|
nat_drift_enabled: bool | None = None
|
|
network_drift_enabled: bool | None = None
|
|
carp_auto_revert_failed_enabled: bool | None = None
|
|
scheduled_maintenance_failed_enabled: bool | None = None
|
|
|
|
poll_interval_seconds: int | None = Field(
|
|
default=None, ge=settings.notification_poll_min_interval_seconds
|
|
)
|
|
|
|
|
|
class NotificationProblemRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: uuid.UUID
|
|
problem_type: ProblemType
|
|
status: Literal["open", "resolved"]
|
|
context: dict
|
|
first_detected_at: datetime
|
|
last_seen_at: datetime
|
|
resolved_at: datetime | None
|
|
last_notified_at: datetime | None
|
|
resolved_notified_at: datetime | None
|
|
|
|
|
|
class TestNotificationRequest(BaseModel):
|
|
channel: Literal["webhook", "email"]
|