Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions orchestrator/orchestrator/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ def _job_cmd(host: str, job: dict, cfg: "Config") -> list[str]:
matching lightweight CLI subcommand — a single TC quarantineWorker call, using
this runner's existing TC creds. "tart-host-update" runs the tart VM host maintenance
flow (orchestrator/tart_host.py); "builder-upgrade" the Intel builder macOS 15 upgrade
(orchestrator/builder_upgrade.py). Anything else is the full reprovision workflow.
(orchestrator/builder_upgrade.py). "reprovision" (or no action: old rows) is the full EACS
workflow. Anything else raises ValueError: a newer Hangar can queue an action this runner
predates, and falling through to `run` would turn it into a wipe.
"""
exe = _reprovision_exe()
action = job.get("action") or "reprovision"
Expand Down Expand Up @@ -234,6 +236,8 @@ def _job_cmd(host: str, job: dict, cfg: "Config") -> list[str]:
if params.get("puppet_only"):
cmd.append("--puppet-only")
return cmd
if action != "reprovision":
raise ValueError(f"unknown action {action!r} -- this runner predates it; update relops-bootstrap")
cmd = [exe, "run", host]
if cfg.unquarantine:
cmd.append("--unquarantine")
Expand All @@ -250,7 +254,11 @@ def _run_job(client: httpx.Client, cfg: Config, job: dict) -> None:
except ValueError as e:
_complete(client, cfg, job_id, False, f"rejected: {e}")
return
cmd = _job_cmd(host, job, cfg)
try:
cmd = _job_cmd(host, job, cfg)
except ValueError as e:
_complete(client, cfg, job_id, False, f"rejected: {e}")
return
_event(client, cfg, job_id, f"runner {cfg.runner_id} starting: {' '.join(cmd[1:])}")
try:
proc = subprocess.Popen(
Expand Down
22 changes: 22 additions & 0 deletions orchestrator/tests/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from unittest.mock import MagicMock, patch

import httpx
import pytest

from orchestrator import runner

Expand Down Expand Up @@ -95,6 +96,27 @@ def test_job_cmd_unquarantine():
assert runner._job_cmd("macmini-m4-80", job, _Cfg()) == ["reprovision", "unquarantine", "macmini-m4-80"]


def test_job_cmd_explicit_reprovision_action_runs_the_workflow():
job = {"action": "reprovision", "params": {}}
assert runner._job_cmd("macmini-m4-80", job, _Cfg())[1:] == ["run", "macmini-m4-80"]


def test_job_cmd_unknown_action_is_rejected_not_run():
# A Hangar newer than this runner can queue an action it doesn't know. Falling through
# to `run` would turn that into an EACS wipe.
with pytest.raises(ValueError, match="unknown action"):
runner._job_cmd("macmini-r8-124", {"action": "some-future-action", "params": {}}, _Cfg())


def test_run_job_fails_unknown_action_without_starting_anything():
client = MagicMock()
with patch("orchestrator.runner.subprocess.Popen") as popen:
runner._run_job(client, _Cfg(), {"id": 11, "short": "macmini-r8-124", "action": "some-future-action"})
popen.assert_not_called()
body = client.post.call_args.kwargs["json"]
assert body["success"] is False and "unknown action" in body["detail"]


def test_complete_retries_until_success():
client = MagicMock()
ok = MagicMock()
Expand Down
Loading