- Добавлен molecule docker create playbook (create.yml + tasks/create_network.yml) с правкой tmpfs: словарь из molecule-plugins приводится к списку строк для community.docker.docker_container; сценарии копируют playbook и задают provisioner.playbooks.create. - Для systemd-платформ tmpfs задаётся списком строк вместо mounts. - В опциях ОС — run_platform (каноническая архитектура после build); в TestHostSpec и hosts теста передаётся platform в molecule/docker_container, чтобы на ARM не падал /sbin/init из-за amd64 без --platform. - Страницы роли (просмотр и создание): одна dashboard-карточка на всю ширину, вкладки Role details / Role file catalog в
167 lines
4.9 KiB
Python
167 lines
4.9 KiB
Python
from datetime import datetime
|
|
from typing import Any
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
class LintRoleFileError(BaseModel):
|
|
line: int | None = None
|
|
column: int | None = None
|
|
level: str = "error"
|
|
message: str = ""
|
|
|
|
|
|
class LintRoleFileRequest(BaseModel):
|
|
path: str = Field(min_length=1, max_length=255)
|
|
content: str = Field(default="", max_length=600_000)
|
|
|
|
|
|
class LintRoleFileResponse(BaseModel):
|
|
ok: bool
|
|
kind: Literal["yaml", "json"]
|
|
errors: list[LintRoleFileError] = Field(default_factory=list)
|
|
|
|
|
|
class RoleFilePayload(BaseModel):
|
|
path: str = Field(min_length=1, max_length=255)
|
|
content: str = ""
|
|
|
|
|
|
class RoleCreate(BaseModel):
|
|
name: str
|
|
source_type: str = Field(description="galaxy | git | inline")
|
|
source_ref: str = ""
|
|
category_id: str | None = None
|
|
description: str = ""
|
|
content: dict[str, Any] | None = None
|
|
files: list[RoleFilePayload] = Field(default_factory=list)
|
|
visibility: str = Field(default="personal", description="public | team | personal (new roles are always personal)")
|
|
team_id: str | None = Field(default=None, description="If set, role is created for this team (visibility=team).")
|
|
tags: list[str] = Field(default_factory=list, description="Labels for filtering and display (comma-separated in UI).")
|
|
os_families: list[str] = Field(
|
|
default_factory=list,
|
|
description="Target OS families: rhel, debian, alpine, suse, arch, bsd, windows, universal.",
|
|
)
|
|
|
|
|
|
class RoleUpdate(BaseModel):
|
|
name: str
|
|
source_type: str = Field(description="galaxy | git | inline")
|
|
source_ref: str = ""
|
|
category_id: str | None = None
|
|
description: str = ""
|
|
visibility: str = Field(default="personal", description="public | team | personal (new roles are always personal)")
|
|
team_id: str | None = Field(default=None, description="Required when setting visibility to team (or omit to keep current team).")
|
|
tags: list[str] = Field(default_factory=list)
|
|
os_families: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class RoleYamlImportRequest(BaseModel):
|
|
name: str
|
|
tasks_yaml: str
|
|
source_ref: str = "imported.yml"
|
|
category_id: str | None = None
|
|
description: str = ""
|
|
files: list[RoleFilePayload] = Field(default_factory=list)
|
|
visibility: str = Field(default="personal", description="public | team | personal (new roles are always personal)")
|
|
tags: list[str] = Field(default_factory=list)
|
|
os_families: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class RoleFilesReplaceRequest(BaseModel):
|
|
files: list[RoleFilePayload]
|
|
visibility: str = Field(default="personal", description="legacy; server assigns visibility on save")
|
|
|
|
|
|
class RoleForkRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=120)
|
|
description: str = ""
|
|
source_type: str = Field(default="inline", description="galaxy | git | inline")
|
|
source_ref: str = ""
|
|
category_id: str | None = None
|
|
|
|
@field_validator("category_id", mode="before")
|
|
@classmethod
|
|
def _empty_category_to_none(cls, v: object) -> str | None:
|
|
if v is None or v == "":
|
|
return None
|
|
return str(v)
|
|
|
|
|
|
class RoleImportItem(BaseModel):
|
|
path: str = Field(min_length=1, max_length=255)
|
|
content: str = ""
|
|
|
|
|
|
class RoleImportResult(BaseModel):
|
|
suggested_name: str
|
|
items: list[RoleImportItem]
|
|
|
|
|
|
class RoleCategoryCreate(BaseModel):
|
|
name: str = Field(min_length=2, max_length=80)
|
|
|
|
|
|
class InventoryCreate(BaseModel):
|
|
name: str
|
|
inventory_text: str
|
|
|
|
|
|
class PlaybookCreate(BaseModel):
|
|
name: str
|
|
description: str = ""
|
|
playbook_yaml: str
|
|
inventory_id: str
|
|
role_ids: list[str] = Field(default_factory=list)
|
|
is_shared: bool = False
|
|
|
|
|
|
class PlaybookYamlImportRequest(BaseModel):
|
|
name: str
|
|
playbook_yaml: str
|
|
inventory_id: str
|
|
description: str = ""
|
|
role_ids: list[str] = Field(default_factory=list)
|
|
is_shared: bool = False
|
|
|
|
|
|
class AddRoleToPlaybookRequest(BaseModel):
|
|
role_id: str
|
|
|
|
|
|
class JobLaunchRequest(BaseModel):
|
|
playbook_id: str
|
|
extra_vars: dict[str, Any] = Field(default_factory=dict)
|
|
runtime_mode: Literal["docker", "k8s"] = "docker"
|
|
|
|
|
|
class JobResponse(BaseModel):
|
|
id: str
|
|
status: str
|
|
celery_task_id: str | None
|
|
created_at: datetime
|
|
|
|
|
|
class TestHostSpec(BaseModel):
|
|
name: str
|
|
image: str = "roleforge-backend:latest"
|
|
groups: list[str] = Field(default_factory=list)
|
|
command: str = "tail -f /dev/null"
|
|
privileged: bool = True
|
|
systemd: bool = False
|
|
# OCI platform for molecule/docker_container (e.g. linux/amd64 on ARM hosts for amd64-only images).
|
|
platform: str = ""
|
|
|
|
|
|
class TestLaunchRequest(BaseModel):
|
|
playbook_id: str | None = None
|
|
role_id: str | None = None
|
|
hosts: list[TestHostSpec] = Field(default_factory=list)
|
|
extra_vars: dict[str, Any] = Field(default_factory=dict)
|
|
runtime_mode: Literal["docker", "k8s"] = "docker"
|
|
|
|
|
|
class RunnerStopRequest(BaseModel):
|
|
runtime_mode: Literal["docker", "k8s"]
|