From c18b7070939e1fe810a2405c0a7f411f4e320429 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 17 Mar 2026 20:17:56 -0400 Subject: [PATCH] feat: add AnsibleRun model and migration 0003 --- .../migrations/versions/0003_ansible_runs.py | 44 +++++++++++++++++++ fablednetmon/models/__init__.py | 2 + fablednetmon/models/ansible.py | 34 ++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 fablednetmon/migrations/versions/0003_ansible_runs.py create mode 100644 fablednetmon/models/ansible.py diff --git a/fablednetmon/migrations/versions/0003_ansible_runs.py b/fablednetmon/migrations/versions/0003_ansible_runs.py new file mode 100644 index 0000000..8cafe08 --- /dev/null +++ b/fablednetmon/migrations/versions/0003_ansible_runs.py @@ -0,0 +1,44 @@ +"""Ansible runs table + +Revision ID: 0003_ansible_runs +Revises: 0002_core_monitors +Create Date: 2026-03-17 +""" +from typing import Sequence, Union +from alembic import op +import sqlalchemy as sa + +revision: str = "0003_ansible_runs" +down_revision: Union[str, None] = "0002_core_monitors" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + "ansible_runs", + sa.Column("id", sa.String(36), primary_key=True), + sa.Column("playbook_path", sa.String(512), nullable=False), + sa.Column("inventory_path", sa.String(512), nullable=False), + sa.Column("source_name", sa.String(128), nullable=False), + sa.Column( + "triggered_by", + sa.String(36), + sa.ForeignKey("users.id", ondelete="RESTRICT"), + nullable=False, + ), + sa.Column( + "status", + sa.Enum("running", "success", "failed", "interrupted", name="ansiblerunstatus"), + nullable=False, + server_default="running", + ), + sa.Column("started_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("output", sa.Text, nullable=True), + ) + + +def downgrade() -> None: + op.drop_table("ansible_runs") + op.execute("DROP TYPE IF EXISTS ansiblerunstatus") diff --git a/fablednetmon/models/__init__.py b/fablednetmon/models/__init__.py index 74ebdd2..33b03a9 100644 --- a/fablednetmon/models/__init__.py +++ b/fablednetmon/models/__init__.py @@ -4,6 +4,7 @@ from .hosts import Host, ProbeType from .monitors import PingResult, DnsResult, PingStatus, DnsStatus from .metrics import PluginMetric from .alerts import AlertRule, AlertState, AlertEvent, AlertOperator, AlertStateEnum +from .ansible import AnsibleRun, AnsibleRunStatus __all__ = [ "Base", "User", @@ -11,4 +12,5 @@ __all__ = [ "PingResult", "DnsResult", "PingStatus", "DnsStatus", "PluginMetric", "AlertRule", "AlertState", "AlertEvent", "AlertOperator", "AlertStateEnum", + "AnsibleRun", "AnsibleRunStatus", ] diff --git a/fablednetmon/models/ansible.py b/fablednetmon/models/ansible.py new file mode 100644 index 0000000..8524fca --- /dev/null +++ b/fablednetmon/models/ansible.py @@ -0,0 +1,34 @@ +from __future__ import annotations +import enum +import uuid +from datetime import datetime, timezone +from sqlalchemy import DateTime, Enum, ForeignKey, String, Text +from sqlalchemy.orm import Mapped, mapped_column +from .base import Base + + +class AnsibleRunStatus(str, enum.Enum): + running = "running" + success = "success" + failed = "failed" + interrupted = "interrupted" + + +class AnsibleRun(Base): + __tablename__ = "ansible_runs" + + id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) + playbook_path: Mapped[str] = mapped_column(String(512), nullable=False) + inventory_path: Mapped[str] = mapped_column(String(512), nullable=False) + source_name: Mapped[str] = mapped_column(String(128), nullable=False) + triggered_by: Mapped[str] = mapped_column( + String(36), ForeignKey("users.id", ondelete="RESTRICT"), nullable=False + ) + status: Mapped[AnsibleRunStatus] = mapped_column( + Enum(AnsibleRunStatus), nullable=False, default=AnsibleRunStatus.running + ) + started_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc) + ) + finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) + output: Mapped[str | None] = mapped_column(Text, nullable=True)