ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
fleet_capacity_client.py
Go to the documentation of this file.
1# SPDX-License-Identifier: MIT
2# Copyright (c) 2026 Brighton Sikarskie
3"""Invoke the declared host-local runner-capacity authority."""
4
5from __future__ import annotations
6
7import sys
8from pathlib import Path
9from typing import Any, Protocol
10
11sys.path.insert(0, str(Path(__file__).resolve().parent))
12
13import fleet_model as fm
14import fleet_reach as fr
15
16CAPACITY_SCRIPT = fm.REPO_ROOT / "scripts" / "ci" / "fleet_capacity.sh"
17
18
19class CommandRunner(Protocol):
20 """Run an exact command while supplying its trusted stdin."""
21
22 def __call__(self, argv: list[str], stdin: str) -> int:
23 """Return the child command status."""
24 ...
25
26
27def _host(data: dict[str, Any], name: str) -> dict[str, Any]:
28 """Return one declared capacity host."""
29 if name not in data["hosts"]:
30 message = f"no host '{name}' in infra/fleet.yml"
31 raise fm.FleetError(message)
32 return data["hosts"][name]
33
34
35def _fail(message: str) -> int:
36 """Emit one capacity precondition failure."""
37 print(f"fleet: error: {message}", file=sys.stderr)
38 return 2
39
40
41def policy_flags(host: dict[str, Any]) -> list[str]:
42 """Return the exact declared capacity and quiet-hours transport flags."""
43 flags = ["--full-instances", str(host["runners"]["instances"])]
44 quiet = host.get("quiet_hours") or {}
45 if not quiet:
46 return flags
47 quiet_start, separator, quiet_end = str(quiet["window"]).partition("-")
48 if separator != "-":
49 message = "quiet-hours window has no start/end separator"
50 raise fm.FleetError(message)
51 return [
52 *flags,
53 "--quiet-instances",
54 str(quiet["instances"]),
55 "--quiet-start",
56 quiet_start,
57 "--quiet-end",
58 quiet_end,
59 "--quiet-days",
60 str(quiet["days"]),
61 ]
62
63
64def state_group(host: dict[str, Any]) -> str:
65 """Return the account group that executes the host-local capacity script."""
66 host_class = fm.CLASSES[host["class"]]
67 if host_class.transport == "wsl":
68 return "root"
69 return str(host["connect"]["user"])
70
71
72def run_selftest(data: dict[str, Any]) -> list[str]:
73 """Prove exact streamed capacity argv for windowed and ordinary hosts."""
74 failures: list[str] = []
75 expected_win = [
76 "--full-instances",
77 "3",
78 "--quiet-instances",
79 "0",
80 "--quiet-start",
81 "18:00",
82 "--quiet-end",
83 "23:59",
84 "--quiet-days",
85 "Fri,Sat,Sun",
86 ]
87 if policy_flags(data["hosts"]["win-ci"]) != expected_win:
88 failures.append("WSL restore argv lost its declared quiet-hours target")
89 expected_nas = ["--full-instances", "2"]
90 if policy_flags(data["hosts"]["truenas"]) != expected_nas:
91 failures.append("ordinary Docker restore argv lost its declared capacity")
92 if state_group(data["hosts"]["win-ci"]) != "root":
93 failures.append("WSL capacity state did not bind to its root executor")
94 if state_group(data["hosts"]["truenas"]) != "truenas_admin":
95 failures.append("SSH capacity state lost its connecting account group")
96 malformed = {**data["hosts"]["win-ci"], "quiet_hours": {"window": "18:00"}}
97 try:
98 policy_flags(malformed)
99 except fm.FleetError:
100 pass
101 else:
102 failures.append("malformed quiet-hours transport was accepted")
103 return failures
104
105
106def run(data: dict[str, Any], name: str, args: list[str], command_runner: CommandRunner) -> int:
107 """Run ``fleet_capacity.sh`` on a host, over that host's transport.
108
109 The script is piped from the checkout on every call rather than invoked
110 from a copy on the host, so an operator command always runs the version in
111 the tree. The copy the ``fleet_capacity`` role installs exists for the
112 unattended quiet-hours timer, which has no checkout to read from.
113
114 Args:
115 data: The parsed declaration.
116 name: Fleet host name.
117 args: Arguments after the fixed configuration flags.
118 command_runner: Exact subprocess transport supplied by the dispatcher.
119
120 Returns:
121 The script's exit status.
122 """
123 host = _host(data, name)
124 cls = fm.CLASSES[host["class"]]
125 if cls.capacity_kind == "none":
126 return _fail(f"{name} is a {host['class']} host and carries no runners to scale")
127 state_group_name = state_group(host)
128 flags = [
129 "--kind",
130 cls.capacity_kind,
131 "--state-group",
132 state_group_name,
133 *policy_flags(host),
134 ]
135 if cls.capacity_kind == "docker":
136 if fm.docker_command(host) != "docker":
137 flags.append("--sudo")
138 for container in fm.container_names(host):
139 flags += ["--container", container]
140 # An operator scale-down must reach the dev slice for the same reason
141 # the timer's does: `just infra::scale HOST=win-ci N=0` is the "I want
142 # to play a game for an hour" command, and it buys the owner nothing
143 # while a gate suite in the slice still has the machine.
144 if host.get("dev_slice"):
145 flags += ["--dev-slice", fm.DEV_SLICE_UNIT]
146 else:
147 flags += ["--scale-set", host["runners"]["labels"][0]]
148 # Never a quoted argument: for the WSL host this line is parsed by Windows'
149 # shell before `wsl -e` sees it, and quoting does not survive that. The
150 # capacity script's flags are shaped so none is ever needed.
151 remote = f"{fm.remote_shell(host)} -- {' '.join(flags)} {' '.join(args)}"
152 return command_runner(
153 [*fr.ssh_target(data, name), remote],
154 stdin=CAPACITY_SCRIPT.read_text(encoding="utf-8"),
155 )