76 lines
3.4 KiB
Python
76 lines
3.4 KiB
Python
from datetime import datetime
|
|
from typing import Any, Optional
|
|
from uuid import uuid4
|
|
|
|
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from sqlalchemy.types import Uuid
|
|
|
|
from .base import Base
|
|
|
|
TASK_STATUSES = ("pending", "running", "success", "partial", "failed", "stale", "cancelled")
|
|
|
|
|
|
class Task(Base):
|
|
__tablename__ = "tasks"
|
|
|
|
id: Mapped[str] = mapped_column(
|
|
Uuid(as_uuid=False), primary_key=True, default=lambda: str(uuid4())
|
|
)
|
|
type: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending")
|
|
target_scope: Mapped[dict] = mapped_column(JSONB, nullable=False)
|
|
params: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
|
|
result: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
|
|
error_message: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
|
|
created_by: Mapped[Optional[int]] = mapped_column(
|
|
Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
started_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
finished_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
heartbeat_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
events: Mapped[list["TaskEvent"]] = relationship(
|
|
"TaskEvent", back_populates="task", cascade="all, delete-orphan"
|
|
)
|
|
device_results: Mapped[list["TaskResult"]] = relationship(
|
|
"TaskResult", back_populates="task", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class TaskEvent(Base):
|
|
__tablename__ = "task_events"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
task_id: Mapped[str] = mapped_column(
|
|
Uuid(as_uuid=False), ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
message: Mapped[str] = mapped_column(Text, nullable=False)
|
|
level: Mapped[str] = mapped_column(String(10), nullable=False, default="info")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
|
|
task: Mapped["Task"] = relationship("Task", back_populates="events")
|
|
|
|
|
|
class TaskResult(Base):
|
|
__tablename__ = "task_results"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
task_id: Mapped[str] = mapped_column(
|
|
Uuid(as_uuid=False), ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
device_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("devices.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending")
|
|
stdout: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
stderr: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
exit_code: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
|
data: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONB, nullable=True)
|
|
duration_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
|
|
executed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
task: Mapped["Task"] = relationship("Task", back_populates="device_results")
|