Files
grm/src/gitea_runner_manager/runner_manager.py
T

94 lines
2.6 KiB
Python

"""Core logic for managing Gitea runners."""
from __future__ import annotations
import os
import subprocess
from pathlib import Path
from typing import Any
from .api_client import GiteaAPIClient
from .exceptions import AnsibleError
class RunnerManager:
"""Orchestrates runner installation and updates."""
def __init__(self, api_client: GiteaAPIClient) -> None:
self.api = api_client
def list_runners(self) -> list[dict[str, Any]]:
"""List all registered runners."""
return self.api.get_runners()
def generate_token(self) -> str:
"""Generate a new registration token."""
return self.api.create_registration_token()
def install(
self,
host: str,
user: str,
key: str | None = None,
name: str | None = None,
token: str | None = None,
) -> None:
"""Install a runner on a remote host using Ansible."""
if not name:
name = host
if not token:
token = self.generate_token()
playbook = Path(__file__).parent.parent.parent / "ansible" / "install-runner.yml"
if not playbook.exists():
raise AnsibleError(f"Playbook not found: {playbook}")
cmd = [
"ansible-playbook",
str(playbook),
"-i",
f"{host},",
"-u",
user,
"--extra-vars",
f"registration_token={token} runner_name={name} gitea_url={self.api.base_url}",
]
if key:
cmd.extend(["--private-key", key])
self._run_ansible(cmd)
def update(
self,
host: str,
user: str,
key: str | None = None,
version: str | None = None,
) -> None:
"""Update the act_runner binary on a remote host."""
playbook = Path(__file__).parent.parent.parent / "ansible" / "update-runner.yml"
if not playbook.exists():
raise AnsibleError(f"Playbook not found: {playbook}")
cmd = [
"ansible-playbook",
str(playbook),
"-i",
f"{host},",
"-u",
user,
]
if key:
cmd.extend(["--private-key", key])
if version:
cmd.extend(["--extra-vars", f"act_runner_version={version}"])
self._run_ansible(cmd)
def _run_ansible(self, cmd: list[str]) -> None:
"""Execute an Ansible command, streaming output."""
env = os.environ.copy()
result = subprocess.run(cmd, env=env, check=False) # noqa: S603
if result.returncode != 0:
raise AnsibleError(f"Ansible failed with exit code {result.returncode}")