Skip to content

fix(setup): seed the REST site record and fix the worker DB target#3284

Open
shayan1995 wants to merge 2 commits into
NVIDIA:mainfrom
shayan1995:fix/site-registration-seed
Open

fix(setup): seed the REST site record and fix the worker DB target#3284
shayan1995 wants to merge 2 commits into
NVIDIA:mainfrom
shayan1995:fix/site-registration-seed

Conversation

@shayan1995

Copy link
Copy Markdown
Contributor

Two defects left a fresh site with an empty nicocli site list despite a healthy, handshaked site-agent:

  1. setup.sh minted a site UUID and the site-agent bootstrap Job POSTed /v1/site to site-manager, which creates the Site CR + OTP — but never the site row in the REST database. The agent handshakes under an identity no REST site matches, so its inventory is dropped.
  2. The nico-pg-cluster consolidation (feat(db): consolidate REST into shared nico-pg-cluster #3081) missed the workflow subchart: site/cloud workers stayed on the legacy postgres.postgres/nico database (zero tables) and failed every DB activity with SQLSTATE 42P01 (relation "site" does not exist), so no site could leave Pending.

Both fixes are contained in setup.sh — the bootstrap Job's existing POST /v1/site flow (Site CR + OTP + temporal certs) is untouched and simply runs after the DB row exists, under the same UUID:

  • Resolve the site UUID instead of blindly minting: explicit NICO_SITE_UUID (bind to a pre-existing site) -> CLUSTER_ID from a prior install's site-agent StatefulSet (stable reruns) -> an existing REST site row with our name (adopt; idempotent reprovision) -> mint. Then seed the REST DB directly with the same record shape as forged's per-env envs/*/carbide-rest/site.sql: a 'default' infrastructure_provider for the org (NICO_ORG, default ncx) plus a Pending site row named after NICO_SITE_NAME / values.yaml siteName, id = created_by = the resolved UUID. All inserts are guarded (WHERE NOT EXISTS) and the seed waits for the REST migrations to have created the tables. IdP-agnostic: no API token required.
  • Delete a site-registration secret bound to a stale UUID so rebinding CLUSTER_ID re-bootstraps instead of silently keeping the old identity.
  • Inject worker DB values at install time via the existing REST creds temp file: nico-rest-workflow now targets nico-pg-cluster/nico_rest as nico-rest.nico with the db-creds secret, aligned with nico-rest-api.

Related issues

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

tested this end to end on dev6

Additional Notes

Two defects left a fresh site with an empty `nicocli site list` despite a
healthy, handshaked site-agent:

1. setup.sh minted a site UUID and the site-agent bootstrap Job POSTed
   /v1/site to site-manager, which creates the Site CR + OTP — but never the
   site row in the REST database. The agent handshakes under an identity no
   REST site matches, so its inventory is dropped.
2. The nico-pg-cluster consolidation (NVIDIA#3081) missed the workflow subchart:
   site/cloud workers stayed on the legacy postgres.postgres/nico database
   (zero tables) and failed every DB activity with SQLSTATE 42P01
   (relation "site" does not exist), so no site could leave Pending.

Both fixes are contained in setup.sh — the bootstrap Job's existing
POST /v1/site flow (Site CR + OTP + temporal certs) is untouched and simply
runs after the DB row exists, under the same UUID:

- Resolve the site UUID instead of blindly minting: explicit NICO_SITE_UUID
  (bind to a pre-existing site) -> CLUSTER_ID from a prior install's
  site-agent StatefulSet (stable reruns) -> an existing REST site row with
  our name (adopt; idempotent reprovision) -> mint. Then seed the REST DB
  directly with the same record shape as forged's per-env
  envs/*/carbide-rest/site.sql: a 'default' infrastructure_provider for the
  org (NICO_ORG, default ncx) plus a Pending site row named after
  NICO_SITE_NAME / values.yaml siteName, id = created_by = the resolved
  UUID. All inserts are guarded (WHERE NOT EXISTS) and the seed waits for
  the REST migrations to have created the tables. IdP-agnostic: no API
  token required.
- Delete a site-registration secret bound to a stale UUID so rebinding
  CLUSTER_ID re-bootstraps instead of silently keeping the old identity.
- Inject worker DB values at install time via the existing REST creds temp
  file: nico-rest-workflow now targets nico-pg-cluster/nico_rest as
  nico-rest.nico with the db-creds secret, aligned with nico-rest-api.

Based on Parham Armani's proposed fix, minimized to avoid chart changes:
the adopt-only bootstrap.yaml rewrite is intentionally not taken — the CR
and DB record are independent artifacts, and ordering the seed before the
existing bootstrap achieves the same invariant.
@shayan1995 shayan1995 requested a review from a team as a code owner July 8, 2026 21:12
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b2573ead-53bc-4372-8ad2-852424e82dd4

📥 Commits

Reviewing files that changed from the base of the PR and between eeb42ab and e668832.

📒 Files selected for processing (3)
  • docs/getting-started/quick-start.md
  • helm-prereqs/README.md
  • helm-prereqs/setup.sh
✅ Files skipped from review due to trivial changes (2)
  • docs/getting-started/quick-start.md
  • helm-prereqs/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • helm-prereqs/setup.sh

Summary by CodeRabbit

  • Bug Fixes
    • Improved workflow connectivity to use the correct REST database and credentials.
    • Made site setup more deterministic by resolving NICO_SITE_UUID from prior configuration, existing REST site data, or provisioning a new UUID.
    • On primary availability, the installer now seeds the REST database idempotently and repairs stale site registration to re-register under the resolved UUID.
  • Documentation
    • Updated Quick Start and prerequisites docs to reflect the new NICO_SITE_UUID behavior across repeated runs.

Walkthrough

Updates helm-prereqs/setup.sh to deterministically resolve NICO_SITE_UUID, seed the REST database when a Patroni primary is available, add workflow DB credentials, and remove stale site-registration state. Matching documentation now reflects the retained/adopted/minted UUID behavior.

Changes

NICo REST bootstrap changes

Layer / File(s) Summary
Workflow DB credentials targeting
helm-prereqs/setup.sh
Adds nico-rest-workflow database connection settings to the generated REST credentials so workflow workers target nico-pg-cluster and the nico_rest database with credentials from db-creds.
Site UUID resolution flow
helm-prereqs/setup.sh, helm-prereqs/README.md, docs/getting-started/quick-start.md
Updates the NICO_SITE_UUID comment and docs to describe deterministic reuse, adoption, or minting of the site UUID when the variable is unset.
REST DB seeding and stale-UUID cleanup
helm-prereqs/setup.sh
Replaces per-run UUID generation with deterministic resolution from the explicit environment value, prior CLUSTER_ID, an existing REST site row by name and org, or a newly minted UUID; then seeds infrastructure_provider, site, and status_detail rows on the Patroni primary, skips seeding without a primary, and deletes a stale site-registration Secret when its UUID no longer matches the resolved value.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant setup.sh
  participant nico-rest-site-agent StatefulSet
  participant Patroni primary
  participant REST PostgreSQL

  setup.sh->>setup.sh: Resolve NICO_SITE_UUID
  setup.sh->>nico-rest-site-agent StatefulSet: Read prior CLUSTER_ID
  setup.sh->>REST PostgreSQL: Look up existing site by name and org
  setup.sh->>setup.sh: Mint UUID with python3 if needed
  setup.sh->>Patroni primary: Discover primary for REST DB writes
  setup.sh->>REST PostgreSQL: Seed site records when primary is available
Loading

Possibly related PRs

  • NVIDIA/infra-controller#3111: Updates the same Quick Start guidance to align with helm-prereqs/setup.sh bootstrap and site registration behavior.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the two main fixes: REST site seeding and the worker DB target correction.
Description check ✅ Passed The description accurately describes both setup.sh fixes and the related behavior changes in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

🧹 Nitpick comments (1)
helm-prereqs/setup.sh (1)

1016-1018: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Suppressing stderr here defeats the very diagnostics the error handlers promise.

_rest_sql routes psql stderr to /dev/null, yet the seeding guards (Lines 1052, 1059) emit only a generic failed to seed …. When an insert genuinely fails, the operator loses the underlying psql/ON_ERROR_STOP message — precisely the actionable detail needed to diagnose a fresh-site provisioning failure. Consider dropping 2>/dev/null on the write path (or capturing and echoing stderr in the failure branch) so the real cause surfaces.

As per path instructions: helm-prereqs/** scripts should provide "clear failure messages."

🤖 Prompt for 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.

In `@helm-prereqs/setup.sh` around lines 1016 - 1018, The _rest_sql helper is
suppressing psql stderr, which hides the real failure details from the seeding
guards that call it. Update _rest_sql in setup.sh so diagnostics from kubectl
exec/su/psql are preserved on the write path, or capture stderr and surface it
in the existing seed-failure handling near the _rest_sql call sites. Keep the
existing helpers and failure branches, but ensure the operator sees the actual
psql/ON_ERROR_STOP error instead of only a generic message.

Source: Path instructions

🤖 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 `@helm-prereqs/setup.sh`:
- Around line 1016-1019: The _rest_sql helper currently runs raw SQL strings,
and the adoption/seeding queries are interpolating NICO_SITE_NAME, NICO_ORG, and
NICO_SITE_UUID directly into those strings, which is unsafe. Update the SQL
execution flow in _rest_sql and its callers to pass these values as psql
variables using -v and reference them in the SQL with :'var' placeholders
instead of shell interpolation. Make sure the affected adoption and seeding
query construction paths use the existing _rest_sql wrapper so the site/org/UUID
values are safely quoted by psql.

---

Nitpick comments:
In `@helm-prereqs/setup.sh`:
- Around line 1016-1018: The _rest_sql helper is suppressing psql stderr, which
hides the real failure details from the seeding guards that call it. Update
_rest_sql in setup.sh so diagnostics from kubectl exec/su/psql are preserved on
the write path, or capture stderr and surface it in the existing seed-failure
handling near the _rest_sql call sites. Keep the existing helpers and failure
branches, but ensure the operator sees the actual psql/ON_ERROR_STOP error
instead of only a generic message.
🪄 Autofix (Beta)

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: 986a4190-7170-4251-9906-916f39066df8

📥 Commits

Reviewing files that changed from the base of the PR and between 1287fdb and 157277a.

📒 Files selected for processing (1)
  • helm-prereqs/setup.sh

Comment thread helm-prereqs/setup.sh
Comment on lines +1016 to +1019
_rest_sql() { # runs SQL against the nico_rest DB on the Patroni primary
kubectl exec -n postgres "${_REST_PG_PRIMARY}" -- \
su postgres -c "psql -d nico_rest -v ON_ERROR_STOP=1 -tAc \"$1\"" 2>/dev/null
}

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant section with line numbers.
sed -n '990,1085p' helm-prereqs/setup.sh | cat -n

# Find _rest_sql usage and nearby variable handling.
rg -n "_rest_sql|NICO_SITE_NAME|NICO_ORG|NICO_SITE_UUID" helm-prereqs/setup.sh

Repository: NVIDIA/infra-controller

Length of output: 9513


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '990,1085p' helm-prereqs/setup.sh | cat -n
rg -n "_rest_sql|NICO_SITE_NAME|NICO_ORG|NICO_SITE_UUID" helm-prereqs/setup.sh

Repository: NVIDIA/infra-controller

Length of output: 9513


Pass site/org/UUID values as psql variables The adoption and seeding queries splice NICO_SITE_NAME, NICO_ORG, and NICO_SITE_UUID directly into SQL literals, so an apostrophe will break the query and arbitrary SQL can be injected. Use psql -v with :'var' placeholders instead of interpolating shell values into the SQL string.

🤖 Prompt for 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.

In `@helm-prereqs/setup.sh` around lines 1016 - 1019, The _rest_sql helper
currently runs raw SQL strings, and the adoption/seeding queries are
interpolating NICO_SITE_NAME, NICO_ORG, and NICO_SITE_UUID directly into those
strings, which is unsafe. Update the SQL execution flow in _rest_sql and its
callers to pass these values as psql variables using -v and reference them in
the SQL with :'var' placeholders instead of shell interpolation. Make sure the
affected adoption and seeding query construction paths use the existing
_rest_sql wrapper so the site/org/UUID values are safely quoted by psql.

Source: Path instructions

@shayan1995 shayan1995 requested a review from polarweasel as a code owner July 8, 2026 21:50
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

@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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/getting-started/quick-start.md`:
- Line 98: Update the NICO_SITE_UUID documentation row to match the actual
bootstrap flow by replacing the reference to the site-agent ConfigMap with the
site-agent StatefulSet environment source. Use the quick-start table entry for
NICO_SITE_UUID as the anchor, and align the wording with setup.sh behavior so
operators know the prior UUID is read from CLUSTER_ID in the site-agent
StatefulSet env before falling back to an existing REST site or minting a new
one.
🪄 Autofix (Beta)

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: 3c669252-765d-43e6-a92b-61e3fe03a72d

📥 Commits

Reviewing files that changed from the base of the PR and between 157277a and eeb42ab.

📒 Files selected for processing (3)
  • docs/getting-started/quick-start.md
  • helm-prereqs/README.md
  • helm-prereqs/setup.sh
✅ Files skipped from review due to trivial changes (1)
  • helm-prereqs/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • helm-prereqs/setup.sh

| `NICO_REST_IMAGE_TAG` | **Yes** | NICo REST image tag (e.g. `v1.0.4`). |
| `KUBECONFIG` | **Yes** | Path to your cluster kubeconfig. |
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` generates a random UUID each run. |
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent ConfigMap), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Align the UUID source with the bootstrap flow.

This row says the prior UUID comes from the site-agent ConfigMap, but the supplied setup.sh context reads CLUSTER_ID from the site-agent StatefulSet env. Please update the docs so operators look at the right object.

-| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent ConfigMap), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |
+| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent StatefulSet env), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent ConfigMap), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent StatefulSet env), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |
🤖 Prompt for 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.

In `@docs/getting-started/quick-start.md` at line 98, Update the NICO_SITE_UUID
documentation row to match the actual bootstrap flow by replacing the reference
to the site-agent ConfigMap with the site-agent StatefulSet environment source.
Use the quick-start table entry for NICO_SITE_UUID as the anchor, and align the
wording with setup.sh behavior so operators know the prior UUID is read from
CLUSTER_ID in the site-agent StatefulSet env before falling back to an existing
REST site or minting a new one.

Post-review hardening of the site-registration seeding, plus seed the site
config with the v2 networking posture:

- Seed config as {"native_networking": true, "network_security_group": true,
  "flow": true} instead of '{}' — the REST create handler defaults the first
  two to true ("new sites default to the v2 networking posture", site.go);
  flow is enabled because these deployments run NICo Flow. Previously all
  capabilities read false via the API.
- Also seed the status_detail row the create handler writes atomically with
  the site row, so status endpoints don't return an empty array (non-fatal).
- Read the prior install's CLUSTER_ID from the nico-rest-site-agent-config
  ConfigMap: the chart delivers it via envFrom, never as an inline env entry,
  so the previous StatefulSet jsonpath always returned empty — resolution
  step 2 and the stale-secret guard were dead code. Fetched once, reused.
- Guard the Patroni-primary lookup with || true: under set -euo pipefail a
  kubectl failure killed the script before the emptiness check that was
  meant to make seeding optional.
- Validate inputs before SQL interpolation: NICO_SITE_UUID must be a UUID,
  NICO_SITE_NAME/NICO_ORG restricted to [A-Za-z0-9][A-Za-z0-9._-]* (they are
  embedded in a double-quoted shell string; a quote would break psql or the
  remote shell).
- Parse siteName from values.yaml regardless of quoting style (bare, single-
  or double-quoted), and don't die under set -e when values.yaml is missing.
- Docs: NICO_SITE_UUID no longer "generates a random UUID each run" — it is
  resolved (prior ConfigMap, adopt-by-name, mint+seed).
@shayan1995 shayan1995 force-pushed the fix/site-registration-seed branch from eeb42ab to e668832 Compare July 8, 2026 21:59

@thossain-nv thossain-nv 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.

Thanks @shayan1995

Comment thread helm-prereqs/setup.sh
fi
if [[ -z "${NICO_SITE_UUID:-}" && -n "${_REST_PG_PRIMARY}" ]]; then
# 3. adopt an existing site row with our name
NICO_SITE_UUID="$(_rest_sql "SELECT id FROM site WHERE name='${NICO_SITE_NAME}' AND org='${NICO_ORG}' AND deleted IS NULL LIMIT 1;" || true)"

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.

If for some reason there's more than 1 Site in DB, we can print Site ID, name and org and print a warning that this is not expected under normal disconnected Site workflow.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
boot-artifacts-aarch64 3 0 0 3 0 0
boot-artifacts-x86_64 3 0 0 3 0 0
forge-admin-cli-x86_64 271 13 34 91 7 126
machine-validation-runner 776 37 223 281 40 195
machine_validation 776 37 223 281 40 195
machine_validation-aarch64 776 37 223 281 40 195
nvmetal-carbide 776 37 223 281 40 195
TOTAL 3381 161 926 1221 167 906

Per-CVE detail lives in the per-service grype-* artifacts (JSON + SARIF). Severity counts only — no CVE IDs published here.

| `NICO_REST_IMAGE_TAG` | **Yes** | NICo REST image tag (e.g. `v1.0.4`). |
| `KUBECONFIG` | **Yes** | Path to your cluster kubeconfig. |
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` generates a random UUID each run. |
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent ConfigMap), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |

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.

If this change works, apply it to the README too :)

Suggested change
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` reuses the UUID from a prior install (site-agent ConfigMap), else adopts an existing REST site with the same name, else mints one and seeds the site record itself. |
| `NICO_SITE_UUID` | No | Stable UUID for this site. If unset, `setup.sh` tries to reuse the UUID from a prior install (site-agent ConfigMap). If that fails, it adopts an existing REST site with the same name, or mints a UUID and seeds the site record itself. |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants