Files
Ansible/scripts/src/aim/playbooks/manager.py
T
2026-09-15 18:54:22 +02:00

91 lines
4.2 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from aim.exceptions import ExternalCommandFailed
from aim.external import command_available, run_external
@dataclass(frozen=True)
class PlaybookSpec:
key: str
name: str
filename: str
category: str
platforms: tuple[str, ...]
extra_vars: tuple[str, ...] = ()
customer_specific: bool = False
ask_pass: bool = False
require_vault: bool = False
PLAYBOOKS: tuple[PlaybookSpec, ...] = (
PlaybookSpec("checkmk_cleanup", "Cleanup CheckMK", "checkmk_cleanup.yml", "CheckMK", ("linux", "windows"), ("checkmk_cleanup_enabled=true",)),
PlaybookSpec("checkmk_install_agent", "Install CheckMK Agent", "checkmk_install_agent.yml", "CheckMK", ("linux", "windows")),
PlaybookSpec("checkmk_update_config", "Update CheckMK Config", "checkmk_update_config.yml", "CheckMK", ("linux", "windows")),
PlaybookSpec("debug_ping", "Ping", "debug_ping.yml", "Debug", ("linux", "windows")),
PlaybookSpec("debug_server_role_selection", "Server Role Selection", "debug_server_role_selection.yml", "Debug", ("linux", "windows")),
PlaybookSpec("debug_disk_usage", "Disk Usage", "debug_disk_usage.yml", "Debug", ("windows",)),
PlaybookSpec("patch_os", "Patch OS", "patch_os.yml", "Maintenance", ("linux", "windows")),
PlaybookSpec("reboot_system", "Reboot System", "reboot_system.yml", "Maintenance", ("linux", "windows")),
PlaybookSpec("backup_eventlog", "Backup Event Log", "backup_eventlog.yml", "Maintenance", ("windows",)),
PlaybookSpec("start_stopped_services", "Start Stopped Services", "start_stopped_services.yml", "Maintenance", ("windows",)),
PlaybookSpec("configure_sophos_initial", "Initial Bitformer Config", "configure_sophos_initial_bitformer_config.yml", "Sophos XGS", ("sophosxgs",), ask_pass=True, require_vault=True),
PlaybookSpec("configure_sophosxgs", "Configure Sophos XGS", "configure_sophosxgs.yml", "Sophos XGS", ("sophosxgs",), customer_specific=True, ask_pass=True, require_vault=True),
)
CATEGORY_ORDER = ("CheckMK", "Debug", "Maintenance", "Sophos XGS")
class PlaybookManager:
def __init__(self, customers, config):
self.customers = customers
self.config = config
@property
def root(self) -> Path:
return self.config.root_dir / "playbooks"
def categories(self) -> list[str]:
return list(CATEGORY_ORDER)
def specs_for_category(self, category: str) -> list[PlaybookSpec]:
return [spec for spec in PLAYBOOKS if spec.category == category]
def path(self, spec: PlaybookSpec, customer: str | None = None) -> Path:
if spec.customer_specific:
if not customer:
raise ValueError(f"Customer is required for playbook {spec.name}")
return self.root / "customers" / customer / spec.filename
return self.root / spec.filename
def available(self, spec: PlaybookSpec, customer: str | None = None) -> bool:
return self.path(spec, customer).is_file()
def run(self, customer: str, inventory: Path, spec: PlaybookSpec, *, limit: str | None = None) -> None:
playbook = self.path(spec, customer)
if not playbook.is_file():
raise FileNotFoundError(playbook)
if not inventory.is_file():
raise FileNotFoundError(inventory)
if not command_available("ansible-playbook"):
raise ExternalCommandFailed("Required command not found: ansible-playbook")
args = ["ansible-playbook", "-i", str(inventory), str(playbook)]
vault = inventory.parent / "group_vars" / "all" / "vault.yml"
if spec.require_vault and not vault.is_file():
raise FileNotFoundError(f"Required customer vault not found: {vault}")
if vault.is_file():
args.extend(["--vault-id", f"{customer}@prompt"])
if spec.ask_pass:
args.append("--ask-pass")
if limit:
args.extend(["--limit", limit])
for extra_var in spec.extra_vars:
args.extend(["-e", extra_var])
result = run_external(args, cwd=self.config.root_dir)
if result.returncode:
raise ExternalCommandFailed(f"Playbook failed with exit code {result.returncode}")