Skip to content

fix: resolve inference.local DNS inside sandbox on macOS - #471

Closed
ross-shulyha wants to merge 3 commits into
NVIDIA:mainfrom
ross-shulyha:fix/inference-local-dns-macos
Closed

fix: resolve inference.local DNS inside sandbox on macOS#471
ross-shulyha wants to merge 3 commits into
NVIDIA:mainfrom
ross-shulyha:fix/inference-local-dns-macos

Conversation

@ross-shulyha

@ross-shulyha ross-shulyha commented Mar 20, 2026

Copy link
Copy Markdown

Summary

On macOS (Docker Desktop and Colima), inference.local is never injected into the k3s CoreDNS configuration by the OpenShell gateway. This means sandbox pods cannot resolve the inference proxy endpoint at https://inference.local/v1, which breaks all local inference (Ollama, vLLM) on Apple Silicon machines.

This PR adds a lightweight DNS fix that runs automatically during nemoclaw onboard on macOS, making local Ollama inference work out of the box — no manual workarounds needed.

Related Issue

Fixes #260macOS/Apple Silicon Support Tracking — Known Gaps & Fixes
Also addresses the DNS resolution aspect of #314.

Changes

  • New file: scripts/fix-inference-dns-macos.sh — Patches the CoreDNS Corefile configmap to add an inline hosts entry mapping inference.local → Traefik ingress ClusterIP (with node IP fallback). The script is idempotent and skips patching if inference.local is already present.
  • Modified: bin/lib/onboard.js — Calls the DNS fix script during gateway setup (step 2) on Darwin, after the existing Colima CoreDNS fix and before sandbox creation.

Type of Change

  • Code change for a new feature, bug fix, or refactor.
  • Code change with doc updates.
  • Doc only. Prose changes without code sample modifications.
  • Doc only. Includes code sample changes.

Testing

  • npm test passes (167/167 tests, 0 failures).
  • Verified end-to-end on macOS 15.4 (Apple M4 Max, Docker Desktop 4.x):
    • nemoclaw onboard with NEMOCLAW_PROVIDER=ollama completes successfully
    • CoreDNS patched: inference.local → 172.18.0.2 (Traefik ClusterIP)
    • Sandbox resolves inference.local and processes inference requests via local Ollama
  • Script is idempotent — re-running onboard does not duplicate the DNS entry.
  • Script is a no-op on Linux (uname -s != Darwin → exits cleanly).

Reproduction steps (before this fix)

# On macOS with Ollama running:
NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_PROVIDER=ollama nemoclaw onboard
# Sandbox created, but inference requests fail:
# "inference.local" does not resolve inside the sandbox pod

After this fix

# Same command now works:
NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_PROVIDER=ollama nemoclaw onboard
# Output includes: "Patching CoreDNS: inference.local -> 172.18.0.2"
# Sandbox successfully routes inference through local Ollama

Checklist

General

Code Changes

  • No secrets, API keys, or credentials committed.
  • Tests added or updated for new or changed behavior.

Summary by CodeRabbit

  • Bug Fixes
    • macOS-only DNS patch added during gateway startup to ensure inference.local resolves inside local cluster sandboxes.
    • Includes a helper script that attempts to inject a hosts mapping and reload DNS inside the local cluster; the step is best-effort and won’t block startup on failure.

On macOS (Docker Desktop / Colima), the OpenShell gateway does not
inject `inference.local` into k3s CoreDNS, so sandbox pods cannot
resolve the inference proxy endpoint at `https://inference.local/v1`.
This breaks local Ollama and vLLM inference on Apple Silicon machines.

Add `scripts/fix-inference-dns-macos.sh` which patches the CoreDNS
Corefile configmap with an inline hosts entry pointing
`inference.local` to the Traefik ingress ClusterIP.  The script runs
automatically during `nemoclaw onboard` (step 2 — gateway setup) on
Darwin, after the existing Colima CoreDNS fix.

Tested on macOS 15.4 (Apple M4 Max) with Docker Desktop and Ollama
local inference — sandbox successfully resolves `inference.local` and
completes inference requests through the local provider.

Fixes NVIDIA#260
@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4ca94dfb-84d1-46e1-92cb-04db40616a38

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5341b and 13c2d3f.

📒 Files selected for processing (1)
  • scripts/fix-inference-dns-macos.sh
✅ Files skipped from review due to trivial changes (1)
  • scripts/fix-inference-dns-macos.sh

📝 Walkthrough

Walkthrough

Adds a macOS-only DNS patch step to onboarding: when running on Darwin, bin/lib/onboard.js invokes scripts/fix-inference-dns-macos.sh, which patches the OpenShell k3s CoreDNS ConfigMap to map inference.local to the gateway IP and restarts CoreDNS.

Changes

Cohort / File(s) Summary
Onboarding Integration
bin/lib/onboard.js
Insert a Darwin-only step inside startGateway(gpu) that logs and runs scripts/fix-inference-dns-macos.sh after existing CoreDNS patch logic; errors are ignored (`
macOS DNS Patch Script
scripts/fix-inference-dns-macos.sh
New executable script (Darwin-only) that selects the OpenShell cluster container, determines a target IPv4 (traefik ClusterIP or node InternalIP), injects an inference.local -> TARGET_IP hosts entry into CoreDNS Corefile (via Python-edited JSON merge patch), applies kubectl patch, and restarts CoreDNS with rollout check.

Sequence Diagram

sequenceDiagram
    participant Onboard as Onboard (bin/lib/onboard.js)
    participant Shell as Local Shell / Container
    participant Kubectl as kubectl / K8s API
    participant ConfigMap as CoreDNS ConfigMap
    participant CoreDNS as CoreDNS Deployment

    Onboard->>Onboard: detect platform === "darwin"
    Onboard->>Shell: run scripts/fix-inference-dns-macos.sh
    Shell->>Shell: find openshell-cluster container
    Shell->>Kubectl: fetch traefik Service / node IPs
    Kubectl-->>Shell: return target IP
    Shell->>ConfigMap: generate JSON merge patch to add hosts mapping
    Shell->>Kubectl: kubectl patch configmap (kube-system coredns)
    Kubectl-->>CoreDNS: apply patch / restart rollout
    CoreDNS-->>Kubectl: rollout status
    Kubectl-->>Shell: patch and rollout acknowledged
    Shell-->>Onboard: script completes (success or ignored errors)
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped into Darwin's DNS glen,

I nudged CoreDNS for hosts to mend,
inference.local now finds the gate,
Sandbox and Ollama celebrate! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding DNS resolution for inference.local inside sandbox on macOS, which is the primary objective of this PR.
Linked Issues check ✅ Passed The PR fully addresses the coding requirement from issue #260: implementing DNS resolution for inference.local on macOS by patching CoreDNS during nemoclaw onboard, enabling local Ollama inference in sandboxes.
Out of Scope Changes check ✅ Passed All code changes are directly related to the stated objective of fixing inference.local DNS resolution on macOS; no unrelated modifications are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
scripts/fix-inference-dns-macos.sh (2)

57-70: Consider validating TARGET_IP format.

While TARGET_IP comes from trusted kubectl output, adding a basic IP format validation before using it in the Corefile would provide defense-in-depth against unexpected kubectl output or edge cases.

🛡️ Optional: Add IP validation
 if [ -z "$TARGET_IP" ]; then
   echo "WARN: Could not determine target IP for inference.local. DNS fix skipped."
   exit 0
 fi
+
+# Basic IP format validation
+if ! echo "$TARGET_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
+  echo "WARN: Invalid IP format '$TARGET_IP'. DNS fix skipped."
+  exit 0
+fi

 echo "Patching CoreDNS: inference.local -> $TARGET_IP"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/fix-inference-dns-macos.sh` around lines 57 - 70, The script
currently uses TARGET_IP (populated via docker exec ... kubectl) without
validating it's a well-formed IP; add a simple validation after the assignments
to ensure TARGET_IP matches IPv4 (or IPv6 if needed) syntax and exit with a
warning if it doesn't. Locate the TARGET_IP variable and the block that echoes
"Patching CoreDNS: inference.local -> $TARGET_IP" and insert a validation check
for the format (e.g., regex test for IPv4 octets or use grep -E) that prints an
error and exits when the value is empty or fails the pattern before exporting
TARGET_IP and patching the Corefile. Ensure the validation covers both attempts
to set TARGET_IP (the traefik svc and the node InternalIP) so bad kubectl output
is rejected.

71-91: Consider adding Corefile format validation.

The Python-based text manipulation is cleaner than sed/awk for this task. However, the marker string 'hosts /etc/coredns/NodeHosts {' on line 75 is brittle—spacing or format changes in k3s CoreDNS could cause silent misses, falling through to the forward . injection path.

Consider logging which injection path was used (NodeHosts vs standalone hosts block) to aid debugging when the patched config doesn't work as expected.

💡 Optional: Add path visibility for debugging
 if marker in corefile:
     corefile = corefile.replace(
         marker,
         marker + '\n      ' + target_ip + ' inference.local'
     )
+    print('DEBUG: Injected into existing NodeHosts block', file=sys.stderr)
 else:
     # No NodeHosts block found — inject a standalone hosts block before
     # the forward directive so inference.local still resolves.
     inject = '    hosts {\n      ' + target_ip + ' inference.local\n      fallthrough\n    }\n'
     if 'forward .' in corefile:
         corefile = corefile.replace('    forward .', inject + '    forward .')
+        print('DEBUG: Injected standalone hosts block before forward', file=sys.stderr)
     else:
         # Last resort: append before closing brace
         corefile = corefile.rstrip().rstrip('}') + inject + '}\n'
+        print('DEBUG: Appended hosts block at end of Corefile', file=sys.stderr)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/fix-inference-dns-macos.sh` around lines 71 - 91, The current
PATCHED_COREFILE python snippet uses a brittle exact marker string ('hosts
/etc/coredns/NodeHosts {') to detect where to inject the host entry and falls
back silently to other injection paths; update the logic in the PATCHED_COREFILE
block to (1) validate the Corefile format before and after modifications (e.g.,
ensure balanced braces and presence of either a NodeHosts block or a forward
directive), (2) match the NodeHosts block using a regex tolerant of
whitespace/indentation (instead of the exact marker), (3) add explicit logging
(to stdout/stderr) that reports which path was taken ("NodeHosts injected",
"standalone hosts injected before forward", or "appended before closing brace")
along with the TARGET_IP and COREFILE preview/summary, and (4) exit non‑zero if
validation fails so callers can detect a bad patch; reference PATCHED_COREFILE,
marker, TARGET_IP and COREFILE when making these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/fix-inference-dns-macos.sh`:
- Around line 57-70: The script currently uses TARGET_IP (populated via docker
exec ... kubectl) without validating it's a well-formed IP; add a simple
validation after the assignments to ensure TARGET_IP matches IPv4 (or IPv6 if
needed) syntax and exit with a warning if it doesn't. Locate the TARGET_IP
variable and the block that echoes "Patching CoreDNS: inference.local ->
$TARGET_IP" and insert a validation check for the format (e.g., regex test for
IPv4 octets or use grep -E) that prints an error and exits when the value is
empty or fails the pattern before exporting TARGET_IP and patching the Corefile.
Ensure the validation covers both attempts to set TARGET_IP (the traefik svc and
the node InternalIP) so bad kubectl output is rejected.
- Around line 71-91: The current PATCHED_COREFILE python snippet uses a brittle
exact marker string ('hosts /etc/coredns/NodeHosts {') to detect where to inject
the host entry and falls back silently to other injection paths; update the
logic in the PATCHED_COREFILE block to (1) validate the Corefile format before
and after modifications (e.g., ensure balanced braces and presence of either a
NodeHosts block or a forward directive), (2) match the NodeHosts block using a
regex tolerant of whitespace/indentation (instead of the exact marker), (3) add
explicit logging (to stdout/stderr) that reports which path was taken
("NodeHosts injected", "standalone hosts injected before forward", or "appended
before closing brace") along with the TARGET_IP and COREFILE preview/summary,
and (4) exit non‑zero if validation fails so callers can detect a bad patch;
reference PATCHED_COREFILE, marker, TARGET_IP and COREFILE when making these
changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 07b54565-e119-49f9-a22b-96553c7b7d7a

📥 Commits

Reviewing files that changed from the base of the PR and between dbfd78c and bb1caa9.

📒 Files selected for processing (2)
  • bin/lib/onboard.js
  • scripts/fix-inference-dns-macos.sh

Address CodeRabbit review feedback — validate that TARGET_IP is a
well-formed IPv4 address before patching the CoreDNS Corefile.
Rejects unexpected kubectl output with a warning instead of
injecting a malformed hosts entry.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/fix-inference-dns-macos.sh`:
- Around line 67-70: The current TARGET_IP validation only checks the
dotted-digit shape and allows out-of-range octets; replace the simple grep with
a stricter IPv4 check that enforces 0-255 per octet. Update the existing
conditional that uses echo "$TARGET_IP" | grep -qE
'^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' to use a regex that validates each octet (for
example:
^((25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})$)
or call a small utility (eg. inet_pton via python -c) to reject invalid numeric
ranges before proceeding with the CoreDNS patch; keep the same warning message
and early exit behavior when validation fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de3b64d2-e9d3-4278-8338-71cb36b7de31

📥 Commits

Reviewing files that changed from the base of the PR and between bb1caa9 and 4f5341b.

📒 Files selected for processing (1)
  • scripts/fix-inference-dns-macos.sh

Comment thread scripts/fix-inference-dns-macos.sh Outdated
Use strict per-octet 0-255 regex instead of simple digit-dot pattern,
as suggested by CodeRabbit review.
@wscurran wscurran added bug platform: macos Affects macOS, including Apple Silicon labels Mar 20, 2026
@wscurran

Copy link
Copy Markdown
Contributor

Thanks for suggesting a fix for the inference.local DNS issue on macOS, this should resolve problems with local inference on Apple Silicon machines.

@wscurran

Copy link
Copy Markdown
Contributor

Thanks for the macOS inference.local DNS fix. This PR has conflicts with the current codebase — the macOS inference path has changed since March. Could you rebase against main and resolve them? Happy to review once it's updated.

@wscurran

Copy link
Copy Markdown
Contributor

Thanks for this — #275 and #464 were tackling the same macOS inference routing issue at the same time. The script-based CoreDNS fix approach here is superseded: scripts/fix-inference-dns-macos.sh is no longer in the codebase, and bin/lib/onboard.js was migrated to TypeScript in PR #1270. Inference routing to the host is now handled via the local-inference.yaml policy preset (PR #2000), which routes host.openshell.internal at the policy level — no DNS script needed.

Closing as superseded. Feel free to reopen if you find gaps in the current macOS local inference path.

@wscurran wscurran closed this Apr 21, 2026
@wscurran wscurran added area: local-models Local model providers, downloads, launch, or connectivity area: providers Inference provider integrations and provider behavior bug-fix PR fixes a bug or regression needs: rebase PR needs rebase or conflict resolution and removed priority: medium labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: local-models Local model providers, downloads, launch, or connectivity area: providers Inference provider integrations and provider behavior bug-fix PR fixes a bug or regression needs: rebase PR needs rebase or conflict resolution platform: macos Affects macOS, including Apple Silicon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macOS/Apple Silicon Support Tracking — Known Gaps & Fixes

3 participants