107 lines
3.6 KiB
Python
107 lines
3.6 KiB
Python
from datetime import datetime
|
|
from enum import Enum
|
|
from typing import Any
|
|
|
|
from sqlalchemy import ForeignKey, func, text
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from src.models import CustomBase, TimestampMixin, IdMixin, DeletedTimestampMixin
|
|
|
|
|
|
class TofuInstanceStatus(Enum):
|
|
ACTIVE = "ACTIVE"
|
|
DEPLOYING = "DEPLOYING"
|
|
DESTROYED = "DESTROYED"
|
|
DESTROYING = "DESTROYING"
|
|
DRIFTED = "DRIFTED"
|
|
FAILED = "FAILED"
|
|
FAILED_DESTROY = "FAILED_DESTROY"
|
|
PENDING = "PENDING"
|
|
PENDING_DESTROY = "PENDING_DESTROY"
|
|
PENDING_DRIFT_CHECK = "PENDING_DRIFT_CHECK"
|
|
|
|
|
|
class TofuInstance(CustomBase, IdMixin, TimestampMixin, DeletedTimestampMixin):
|
|
__tablename__ = "tofu_instance"
|
|
|
|
status: Mapped[TofuInstanceStatus] = mapped_column(default=TofuInstanceStatus.PENDING)
|
|
configuration: Mapped[dict[str, Any]]
|
|
outputs: Mapped[dict[str, Any] | None]
|
|
plan: Mapped[dict[str, Any] | None]
|
|
state: Mapped[dict[str, Any] | None]
|
|
state_password: Mapped[bytes | None]
|
|
state_lock: Mapped[dict[str, Any] | None]
|
|
status_changed_at: Mapped[datetime] = mapped_column(default=func.now())
|
|
drift_checked_at: Mapped[datetime | None]
|
|
tasks = relationship("TofuInstanceTask", back_populates="instance")
|
|
status_changes = relationship("TofuInstanceStatusChange", back_populates="instance")
|
|
|
|
|
|
class TofuInstanceStatusChange(CustomBase, IdMixin):
|
|
__tablename__ = "tofu_instance_status_change"
|
|
|
|
instance_id: Mapped[int] = mapped_column(ForeignKey("tofu_instance.id"))
|
|
instance_task_id: Mapped[int] = mapped_column(ForeignKey("tofu_instance_task.id"))
|
|
timestamp: Mapped[datetime] = mapped_column(default=func.now())
|
|
old_status: Mapped[TofuInstanceStatus]
|
|
new_status: Mapped[TofuInstanceStatus]
|
|
instance = relationship("TofuInstance", back_populates="status_changes")
|
|
|
|
|
|
class TofuInstanceTaskType(Enum):
|
|
CHECK_DRIFT = "CHECK_DRIFT"
|
|
DEPLOY = "DEPLOY"
|
|
DESTROY = "DESTROY"
|
|
|
|
|
|
class TofuInstanceTaskStatus(Enum):
|
|
CANCELED = "CANCELED"
|
|
COMPLETED = "COMPLETED"
|
|
FAILED = "FAILED"
|
|
PENDING = "PENDING"
|
|
RUNNING = "RUNNING"
|
|
|
|
|
|
class TofuInstanceTask(CustomBase, IdMixin, TimestampMixin):
|
|
__tablename__ = "tofu_instance_task"
|
|
|
|
instance_id: Mapped[int] = mapped_column(ForeignKey("tofu_instance.id"))
|
|
task: Mapped[TofuInstanceTaskType]
|
|
status: Mapped[TofuInstanceTaskStatus] = mapped_column(
|
|
default=TofuInstanceTaskStatus.PENDING
|
|
)
|
|
start_time: Mapped[datetime | None]
|
|
end_time: Mapped[datetime | None]
|
|
instance = relationship("TofuInstance", back_populates="tasks")
|
|
|
|
|
|
class TofuInstanceTaskLog(CustomBase, IdMixin):
|
|
__tablename__ = "tofu_instance_task_log"
|
|
|
|
instance_task_id: Mapped[int] = mapped_column(ForeignKey("tofu_instance_task.id"))
|
|
timestamp: Mapped[datetime] = mapped_column(default=func.now())
|
|
log: Mapped[dict[str, Any]]
|
|
|
|
|
|
class TofuBruteForce(CustomBase, IdMixin, TimestampMixin):
|
|
__tablename__ = "tofu_brute_force"
|
|
|
|
host: Mapped[str]
|
|
expiry: Mapped[datetime] = mapped_column(default=func.now() + text("INTERVAL '1 hour'"))
|
|
|
|
|
|
def update_tofu_instance_status(
|
|
db: AsyncSession, instance: TofuInstance, task_id: int, new_status: TofuInstanceStatus
|
|
) -> None:
|
|
status_change = TofuInstanceStatusChange(
|
|
instance_id=instance.id,
|
|
instance_task_id=task_id,
|
|
old_status=instance.status,
|
|
new_status=new_status,
|
|
)
|
|
db.add(status_change)
|
|
instance.status = new_status
|
|
instance.status_changed_at = func.now()
|
|
if new_status == TofuInstanceStatus.DESTROYED:
|
|
instance.deleted_at = func.now()
|