91 lines
4.2 KiB
Python
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}")
|