62 lines
2.4 KiB
Python
62 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
from uuid import uuid4
|
|
|
|
from app.core.constants import (
|
|
SOFTWARE_A_TASK_STATUS_FAILED,
|
|
SOFTWARE_A_TASK_STATUS_RUNNING,
|
|
SOFTWARE_A_TASK_STATUS_SUCCEEDED,
|
|
)
|
|
from app.core.time import format_now
|
|
from app.schemas.software_a import CreateDeployTaskRequest
|
|
|
|
|
|
class SoftwareAService:
|
|
_deploy_tasks: dict[str, dict] = {}
|
|
|
|
def __init__(self, timezone_name: str) -> None:
|
|
self.timezone_name = timezone_name
|
|
|
|
def create_deploy_task(self, payload: CreateDeployTaskRequest) -> dict:
|
|
task_id = f"sa-task-{uuid4().hex[:12]}"
|
|
should_fail = self._should_fail_deploy(payload)
|
|
task_status = SOFTWARE_A_TASK_STATUS_FAILED if should_fail else SOFTWARE_A_TASK_STATUS_RUNNING
|
|
error_detail = self._build_error_detail(payload) if should_fail else None
|
|
task = {
|
|
"software_a_task_id": task_id,
|
|
"task_status": task_status,
|
|
"progress_percent": 100,
|
|
"app_code": payload.app_code,
|
|
"env": payload.env,
|
|
"version": payload.version,
|
|
"target_nodes": payload.target_nodes,
|
|
"started_at": format_now(self.timezone_name),
|
|
"finished_at": format_now(self.timezone_name),
|
|
"error_detail": error_detail,
|
|
}
|
|
self._deploy_tasks[task_id] = task
|
|
return task
|
|
|
|
def get_deploy_task(self, software_a_task_id: str) -> dict | None:
|
|
task = self._deploy_tasks.get(software_a_task_id)
|
|
if not task:
|
|
return None
|
|
if task["task_status"] == SOFTWARE_A_TASK_STATUS_FAILED:
|
|
return task
|
|
task["task_status"] = SOFTWARE_A_TASK_STATUS_SUCCEEDED
|
|
task["progress_percent"] = 100
|
|
return task
|
|
|
|
def check_permission(self, action_type: str, env: str, approval_status: str | None = None) -> tuple[bool, str]:
|
|
if env == "prod" and action_type in {"STOP_SERVICE", "RESTART_SERVICE", "DEPLOY"} and approval_status != "APPROVED":
|
|
return False, "生产环境动作默认需要额外审批"
|
|
return True, ""
|
|
|
|
def _should_fail_deploy(self, payload: CreateDeployTaskRequest) -> bool:
|
|
app_code = payload.app_code.lower()
|
|
version = payload.version.lower()
|
|
return "fail" in app_code or "fail" in version
|
|
|
|
def _build_error_detail(self, payload: CreateDeployTaskRequest) -> str:
|
|
return f"demo deploy failed for app={payload.app_code}, env={payload.env}, version={payload.version}"
|