diff --git a/src/ci_orchestrator/commands/job.py b/src/ci_orchestrator/commands/job.py index f566f22..8654fd8 100644 --- a/src/ci_orchestrator/commands/job.py +++ b/src/ci_orchestrator/commands/job.py @@ -22,6 +22,7 @@ import shutil import subprocess import sys import tempfile +import signal import time import uuid from datetime import UTC, datetime @@ -473,6 +474,12 @@ def job( phase_timings: list[tuple[str, float]] = [] phase_start = _now() + # SIGTERM (sent by act_runner on workflow cancellation) must trigger cleanup. + def _sigterm(_sig: int, _frame: object) -> None: + raise KeyboardInterrupt() + + signal.signal(signal.SIGTERM, _sigterm) + click.echo("=" * 60) click.echo(f"[job] Job : {job_id}") click.echo(f"[job] Repository : {repo_url}") @@ -508,7 +515,14 @@ def job( ) _apply_vmx_overrides(clone_vmx, guest_cpu, guest_memory_mb) - if config.ip_pool is not None: + # Resolve guest OS before IP-pool guard — Linux doesn't read guestinfo IP. + if guest_os.lower() == "auto": + guest_os = _read_guest_os_from_vmx(clone_vmx) + click.echo(f"[job] auto-detected guest OS: {guest_os}") + else: + guest_os = guest_os.lower() + + if config.ip_pool is not None and guest_os != "linux": slot_pool = IpSlotPool( addresses=config.ip_pool.addresses, netmask=config.ip_pool.netmask, @@ -531,13 +545,6 @@ def job( except BackendError as exc: raise click.ClickException(f"vmrun start failed: {exc}") from exc - # Resolve guest OS now that the clone exists. - if guest_os.lower() == "auto": - guest_os = _read_guest_os_from_vmx(clone_vmx) - click.echo(f"[job] auto-detected guest OS: {guest_os}") - else: - guest_os = guest_os.lower() - deadline = _now() + ready_timeout if not _wait_running(backend, handle, deadline, poll_interval): raise click.ClickException("timeout waiting for VM to be running.")