fix(nemo-deployments): gate OpenShell READY on a curl reachability probe - #1259
Conversation
The readiness gate added in #1139 never ran. It located an interpreter with `command -v python3 || command -v python`, but packaged agent images ship Python only in /workspace/.venv, which is not on the exec PATH. With no interpreter found, the probe took its `else exit 0` branch, which the gate reads as reachable, so READY was published about 14s before nat serve bound its port. Probe with curl instead. curl is present in these images (the NAT and Fabric Dockerfiles install it, and the sandbox policy pins /usr/bin/curl) and is resolved at that absolute path with a PATH fallback. A missing curl now exits nonzero, so the gate fails closed. - httpGet: curl --fail --insecure (5xx not-ready, self-signed loopback ok) - tcpSocket and default: loopback connect classified by curl exit code (7 = refused = not-ready, any other exit = ready) - deploy-sandbox SKILL: drop the "retry a 502 for 30-60s" guidance, since READY now means the port is reachable - integration: add a slow-bind regression test that asserts READY waits for bind Fixes AIRCORE-998. Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
|
📝 WalkthroughWalkthroughChangesOpenShell readiness probes now use OpenShell readiness
Sequence Diagram(s)sequenceDiagram
participant OpenShellBackend
participant Curl
participant Workload
OpenShellBackend->>Curl: Run HTTP or TCP readiness probe
Curl->>Workload: Connect to loopback port
Workload-->>Curl: Return response or connection result
Curl-->>OpenShellBackend: Return exit status
OpenShellBackend-->>OpenShellBackend: Set readiness state
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@plugins/nemo-deployments/src/nemo_deployments_plugin/backends/openshell/backend.py`:
- Around line 830-839: Add --noproxy '*' to every curl invocation generated by
_curl_probe_script in backend.py, covering both HTTP and TCP probes. Update
test_backend.py lines 773-797 to assert the option appears in both generated
probe commands.
In
`@plugins/nemo-deployments/src/nemo_deployments_plugin/skills/deploy-sandbox/SKILL.md`:
- Line 289: Update the readiness guidance in SKILL.md to remove the stale
instruction to wait after READY because readiness now includes port binding.
Keep the recovery guidance explaining that a 502 indicates nat serve on port
9000 is not answering and directs users to the serve log.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 7c2fb00a-d223-49d3-aec0-bad87ebdeda4
📒 Files selected for processing (4)
plugins/nemo-deployments/src/nemo_deployments_plugin/backends/openshell/backend.pyplugins/nemo-deployments/src/nemo_deployments_plugin/skills/deploy-sandbox/SKILL.mdplugins/nemo-deployments/tests/integration/backends/openshell/test_openshell_backend.pyplugins/nemo-deployments/tests/unit/backends/openshell/test_backend.py
Loopback readiness probes ran plain curl, so http_proxy/https_proxy in the sandbox image env would route the 127.0.0.1 request through a proxy. For the TCP probe (exit 7 = not-ready, anything else = ready) a reachable-but-erroring proxy returns a non-7 code, flipping the deployment to READY before nat serve binds its port -- the exact race this gate closes. Add --noproxy '*' to both the httpGet and TCP probe curls, and assert it in the unit tests. Also drop the stale 'give serve a moment after READY' note in the deploy skill: READY now gates on a reachability probe, so the endpoint serves as soon as it reports READY. Signed-off-by: Max Dubrinsky <mdubrinsky@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@plugins/nemo-deployments/src/nemo_deployments_plugin/skills/deploy-sandbox/SKILL.md`:
- Line 275: Update the deployment command flow around the status polling and
recovery-table transition to add an explicit guard that exits before extracting
URL or reaching Step 6 unless status equals READY. Preserve the existing
recovery handling for FAILED and timed-out PENDING/STARTING states.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 90aa0afc-8c27-40f5-97a8-49ac2645826c
📒 Files selected for processing (3)
plugins/nemo-deployments/src/nemo_deployments_plugin/backends/openshell/backend.pyplugins/nemo-deployments/src/nemo_deployments_plugin/skills/deploy-sandbox/SKILL.mdplugins/nemo-deployments/tests/unit/backends/openshell/test_backend.py
🚧 Files skipped from review as they are similar to previous changes (2)
- plugins/nemo-deployments/src/nemo_deployments_plugin/backends/openshell/backend.py
- plugins/nemo-deployments/tests/unit/backends/openshell/test_backend.py
Summary
The readiness gate added in #1139 never ran: it located an interpreter with
command -v python3 || command -v python, but packaged agent images ship Python only in/workspace/.venv, which is not on the exec PATH, so the probe hit itselse exit 0branch and the gate read that as reachable. READY was published about 14s beforenat servebound its port. This probes withcurlinstead, resolved at/usr/bin/curl(installed by the NAT and Fabric Dockerfiles, pinned by the sandbox policy) with a PATH fallback, and fails closed when curl is absent, so READY now means the port is reachable.Related Issue
AIRCORE-998 (NVBug 6567588). Reopened by QA after #1139 did not change the measured behavior.
Changes
openshell/backend.py; a missing curl exits nonzero (fails closed) instead of exiting 0.curl --fail --insecure(a 5xx reads as not-ready; a self-signed loopback cert is accepted).telnet://was rejected because curl stays connected until--max-timeon a live port.deploy-sandboxSKILL: drop the "retry a 502 for 30-60s" guidance now that READY implies reachability.Type of Change
Quality Gates
Verification
Signed-off-by:traileruv run pre-commit run -apasses, or any blocked checks are identified belowTargeted validation:
uv run pre-commit run --files <4 changed files>: passed (ruff, ruff format, ty, copyright headers, plugin-import check, merge-conflict check). Fullpre-commit run -anot run locally (heavy container hooks such as helm-docs and OpenAPI generation are irrelevant to these files); left to CI.pytest plugins/nemo-deployments/tests/unit/backends/openshell/test_backend.pywith theopenshellextra: 71 passed, including a new fail-closed test.pytest plugins/nemo-deployments/tests/integration/backends/openshell/test_openshell_backend.pyagainst a live gateway (v0.0.92, docker driver): 2 passed, including a new slow-bind test asserting READY waits for bind.openshell sandbox exec(the backend's own exec path): unbound port -> curl exit 7 (not-ready); bound socket -> curl exit 0 (ready); with no Python on PATH the old probe exits 0 (READY, reproducing the bug) while the new probe exits 1 (STARTING, fixed).Summary by CodeRabbit
Bug Fixes
Tests