Skip to content

feat(rest-api): add iPXE template + templated-OS data model & proto - #3160

Merged
pbreton merged 2 commits into
NVIDIA:mainfrom
pbreton:feat/ipxe-templated-os-1
Jul 7, 2026
Merged

feat(rest-api): add iPXE template + templated-OS data model & proto#3160
pbreton merged 2 commits into
NVIDIA:mainfrom
pbreton:feat/ipxe-templated-os-1

Conversation

@pbreton

@pbreton pbreton commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

First PR in a clean, reviewable stack that ports the Templated iPXE Operating System feature onto REST API to match 'core' implementation. This PR lands only the data-model + proto foundation; the sync workflow and the API/SDK/OpenAPI layers follow in subsequent stacked PRs (see Stack below). It introduces an iPXE template–based OS variant (alongside Image and raw iPXE) with a per-OS scope (Local / Global / Limited) and the schema that lets OS definitions stay in sync with on-site NICo Core.

This PR is data-layer only: no handler, workflow, or route wiring is activated yet, so it is additive and inert on its own.

Stack

  • PR 1 (this PR) — DB data model + proto/inventory foundation
  • PR 2 (coming) — cloud sync workflow (inbound reconcile + OS / iPXE-template inventory workflows)
  • PR 3 (coming) — API handler (Core gRPC proxy push branch), iPXE-template endpoints, route wiring, OpenAPI + Go SDK, site-agent / site-workflow collectors

What's implemented

  • DB schemaoperating_system scope + iPXE template columns; new ipxe_template and ipxe_template_site_association tables; operating_system_site_association.controller_state; additive migration (20260623150000_ipxe_os_and_templates).
  • DB modelsipxetemplate and ipxetemplatesiteassociation DAOs, extended operatingsystem model (scope + templated-iPXE type), and proto conversions.
  • ProtoOperatingSystemInventory + IpxeTemplateInventory added to inventory.proto (regenerated; only inventory.pb.go changed) so the downstream inbound-inventory PR has the types it needs.
  • Tests — model tests for ipxetemplate, ipxetemplatesiteassociation, and the templated/scope additions to operatingsystem (table-driven).

Verification

  • Tests PASS: cd rest-api && make test

Notes for review

  • Migration is additive ; existing Image and raw iPXE behavior is untouched.
  • controller_state on operating_system_site_association is introduced here but is exercised by the later workflow/API PRs.
  • Only inventory.pb.go changes in the generated proto; no other generated files are touched in this PR.

Type of Change

  • Feature (feat:)

Services Affected

  • DB · [x] Proto (inventory) — Workflow / API / Site Agent land in later PRs of this stack

Breaking Changes

None expected — additive schema + new proto messages only.

PR 1/3 (foundations). Adds DB models and site-agent inventory proto for
iPXE templates and templated iPXE Operating Systems:

- IpxeTemplate + IpxeTemplateSiteAssociation models (+ tests)
- OperatingSystem iPXE/templated fields and scope handling (+ tests)
- OperatingSystemSiteAssociation updates
- StatusDetailDAO.CreateFromParams helper
- Migration 20260623150000_ipxe_os_and_templates
- site-agent workflows v1 inventory proto: OperatingSystem/template types
@pbreton
pbreton requested a review from a team as a code owner July 6, 2026 22:21
@pbreton pbreton self-assigned this Jul 6, 2026
@pbreton
pbreton requested a review from thossain-nv July 6, 2026 22:21
@coderabbitai

coderabbitai Bot commented Jul 6, 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: 71a9c3e8-f9a4-46ea-ae3b-1cb17897e97f

📥 Commits

Reviewing files that changed from the base of the PR and between 011d2a3 and 53fdc38.

📒 Files selected for processing (4)
  • rest-api/db/pkg/db/model/ipxetemplate.go
  • rest-api/db/pkg/db/model/ipxetemplate_test.go
  • rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go
  • rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go
  • rest-api/db/pkg/db/model/ipxetemplate_test.go
  • rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go
  • rest-api/db/pkg/db/model/ipxetemplate.go

Summary by CodeRabbit

  • New Features
    • Added database-backed iPXE template management with site associations (including association uniqueness).
    • Extended operating system records to store iPXE template content, parameters/artifacts, definition hash, and scope.
    • Added inventory responses for operating system definitions and iPXE templates.
  • Bug Fixes
    • Improved timestamp handling and partial update behavior for templates and iPXE OS fields.
    • Strengthened scope filtering and default handling for iPXE-related data.
  • Tests
    • Added SQL DAO integration tests for templates, template-site associations, uniqueness, pagination/filtering, and iPXE OS scope flows.

Walkthrough

Adds iPXE template persistence, operating-system templating support, controller-state tracking for site associations, a schema migration, and new inventory protobuf messages.

Changes

iPXE Template Support

Layer / File(s) Summary
IpxeTemplate model, DAO, and tests
rest-api/db/pkg/db/model/ipxetemplate.go, rest-api/db/pkg/db/model/ipxetemplate_test.go
Defines the iPXE template model, DAO, timestamp hook, CRUD/listing behavior, and tests for create/get/update/delete, filtering, pagination, uniqueness, and default slices.
IpxeTemplateSiteAssociation model, DAO, and tests
rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go, rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go
Defines the template-to-site association model, relation hooks, DAO operations, and tests for composite lookup, listing, uniqueness, and deletion.
OperatingSystem iPXE templating fields, scope, and DAO logic
rest-api/db/pkg/db/model/operatingsystem.go, rest-api/db/pkg/db/model/operatingsystem_ipxe_test.go
Extends OperatingSystem with iPXE template fields, scope, cache-strategy mappings, create/update/clear/filter behavior, and tests for round-trip persistence and scope filtering.
OperatingSystemSiteAssociation controller state
rest-api/db/pkg/db/model/operatingsystemsiteassociation.go
Adds ControllerState to the association model and write paths, with tenant-state-to-status mapping.
Migration and inventory proto schema
rest-api/db/pkg/migrations/20260623150000_ipxe_os_and_templates.go, rest-api/workflow-schema/site-agent/workflows/v1/inventory.proto
Adds the migration for iPXE tables/columns/backfill and introduces new inventory messages for operating systems and iPXE templates.

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

Related Issues: None

Related PRs: None

Suggested labels: database, migration, feature

Suggested reviewers: Reviewers familiar with the Bun DAO layer and iPXE/OperatingSystem persistence flow

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main addition: iPXE template and templated-OS data model/proto support.
Description check ✅ Passed The description matches the changeset and accurately describes the new data-model, proto, and migration work.
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.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
nico-flow 12 1 2 2 0 7
nico-nsm 4 0 0 4 0 0
nico-psm 12 1 2 2 0 7
nico-rest-api 12 1 2 2 0 7
nico-rest-cert-manager 12 1 2 2 0 7
nico-rest-db 12 1 2 2 0 7
nico-rest-site-agent 12 1 2 2 0 7
nico-rest-site-manager 12 1 2 2 0 7
nico-rest-workflow 12 1 2 2 0 7
TOTAL 100 8 16 20 0 56

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

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-07-06 22:23:57 UTC | Commit: 011d2a3

@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: 2

🧹 Nitpick comments (5)
rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go (1)

59-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Composite uniqueness constraint lives only in the migration, not the model.

The (ipxe_template_id, site_id) uniqueness invariant is applied entirely via raw SQL in the migration (and duplicated again in the test setup), but nothing in the model itself documents or enforces it — unlike the FK constraints, which are colocated in BeforeCreateTable. Anyone using ResetModel (as the tests do) outside of this specific test helper would miss the constraint entirely. Consider adding the UNIQUE constraint inside BeforeCreateTable alongside the ForeignKey calls so the invariant travels with the model.

Also applies to: 79-86

🤖 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 `@rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go` around lines 59 -
64, The composite uniqueness for the ipxe_template/site association is currently
only enforced in migration SQL and test setup, so it is easy to miss when the
model is reset elsewhere. Update IpxeTemplateSiteAssociation’s BeforeCreateTable
method to declare the (ipxe_template_id, site_id) UNIQUE constraint alongside
the existing ForeignKey calls, so the invariant is defined with the model rather
than only in migrations.
rest-api/db/pkg/migrations/20260623150000_ipxe_os_and_templates.go (1)

40-50: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Redundant index on ipxe_template.name.

IpxeTemplate.Name is tagged unique in the Bun model (ipxetemplate.go Line 51), so tx.NewCreateTable() already produces a UNIQUE constraint on name, which Postgres backs with an implicit unique b-tree index (confirmed by the test files re-creating ipxe_template_name_key, the default Postgres constraint name for that exact column). The subsequent CREATE INDEX ipxe_template_name_idx ON ipxe_template(name) therefore duplicates that index, adding unnecessary write overhead and storage with no query benefit.

♻️ Proposed fix
-		_, err = tx.Exec("CREATE INDEX IF NOT EXISTS ipxe_template_name_idx ON ipxe_template(name)")
-		handleError(tx, err)
 		_, err = tx.Exec("CREATE INDEX IF NOT EXISTS ipxe_template_scope_idx ON ipxe_template(scope)")

As per path instructions, "Review database changes for Bun/pgx query correctness, transaction boundaries, migration ordering, data-model compatibility."

🤖 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 `@rest-api/db/pkg/migrations/20260623150000_ipxe_os_and_templates.go` around
lines 40 - 50, Remove the redundant name index from the ipxe template migration:
the IpxeTemplate model already makes name unique, so tx.NewCreateTable() will
create the implicit unique index for it. In the migration logic around the
IpxeTemplate table creation, keep only the non-duplicate indexes (scope,
created, updated) and drop the extra CREATE INDEX on name to avoid unnecessary
storage and write overhead.

Source: Path instructions

rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go (1)

17-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated schema-bootstrap SQL across test files.

The ipxe_template_name_key drop/add block (Lines 25-28) exactly duplicates the identical statements in ipxetemplate_test.go's testIpxeTemplateSetupSchema. Consider extracting a shared helper (e.g. testIpxeTemplateAddUniqueConstraint) to avoid the two copies drifting apart if the constraint definition ever changes.

🤖 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 `@rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go` around lines 17
- 33, The schema bootstrap in testIpxeTemplateSiteAssociationSetupSchema
duplicates the ipxe_template unique-constraint drop/add logic already used in
testIpxeTemplateSetupSchema; extract that repeated ALTER TABLE sequence into a
shared helper with a clear name such as a constraint bootstrap helper, then call
it from both test setup functions so the ipxe_template_name_key definition stays
consistent in one place.
rest-api/db/pkg/db/model/operatingsystem.go (2)

129-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse IsIPXEType instead of re-listing the iPXE type set inline.

GetAll's scope filter hardcodes []string{OperatingSystemTypeIPXE, OperatingSystemTypeTemplatedIPXE}, duplicating the exact set already encapsulated by the newly-added IsIPXEType. If a third iPXE variant is ever introduced, only one of the two call sites is likely to be updated, silently breaking scope filtering for the new type.

♻️ Proposed fix
+var operatingSystemIPXETypes = []string{OperatingSystemTypeIPXE, OperatingSystemTypeTemplatedIPXE}
+
 // IsIPXEType returns true if the given OS type is any iPXE variant (raw script or templated).
 func IsIPXEType(osType string) bool {
-	return osType == OperatingSystemTypeIPXE || osType == OperatingSystemTypeTemplatedIPXE
+	return slices.Contains(operatingSystemIPXETypes, osType)
 }
 		query = query.Where(
 			"os.type IN (?) AND COALESCE(os.ipxe_os_scope, ?) IN (?)",
-			bun.In([]string{OperatingSystemTypeIPXE, OperatingSystemTypeTemplatedIPXE}),
+			bun.In(operatingSystemIPXETypes),
 			OperatingSystemScopeLocal,
 			bun.In(filter.Scopes),
 		)

Also applies to: 629-639

🤖 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 `@rest-api/db/pkg/db/model/operatingsystem.go` around lines 129 - 132, The
scope filter in GetAll is duplicating the iPXE type list inline instead of
reusing IsIPXEType, which risks drift if more iPXE variants are added. Update
the filtering logic in GetAll to use IsIPXEType as the single source of truth
for identifying iPXE OS types, and remove the hardcoded
[]string{OperatingSystemTypeIPXE, OperatingSystemTypeTemplatedIPXE} set so both
call sites stay consistent.

62-69: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a named CacheStrategy type instead of raw strings + package-level maps.

OperatingSystemIpxeArtifact.CacheStrategy is a bare string, with proto round-tripping handled by two package-level maps invoked inline inside FromProto/ToProto. The repo's established pattern for exactly this situation—a string field that round-trips with a proto enum—is a dedicated named type owning its own ToProto/FromProto methods.

♻️ Proposed refactor sketch
-type OperatingSystemIpxeArtifact struct {
-	Name          string  `json:"name"`
-	URL           string  `json:"url"`
-	SHA           *string `json:"sha"`
-	AuthType      *string `json:"authType"`
-	AuthToken     *string `json:"authToken"`
-	CacheStrategy string  `json:"cacheStrategy"`
-}
+type OperatingSystemIpxeArtifactCacheStrategy string
+
+func (s OperatingSystemIpxeArtifactCacheStrategy) ToProto() cwssaws.IpxeTemplateArtifactCacheStrategy {
+	return OperatingSystemIpxeArtifactCacheStrategyToProtoMap[string(s)]
+}
+
+func (s *OperatingSystemIpxeArtifactCacheStrategy) FromProto(p cwssaws.IpxeTemplateArtifactCacheStrategy) {
+	v := OperatingSystemIpxeArtifactCacheStrategyFromProtoMap[p]
+	if v == "" {
+		v = OperatingSystemIpxeArtifactCacheStrategyCacheAsNeeded
+	}
+	*s = OperatingSystemIpxeArtifactCacheStrategy(v)
+}
+
+type OperatingSystemIpxeArtifact struct {
+	Name          string                                     `json:"name"`
+	URL           string                                     `json:"url"`
+	SHA           *string                                    `json:"sha"`
+	AuthType      *string                                    `json:"authType"`
+	AuthToken     *string                                    `json:"authToken"`
+	CacheStrategy OperatingSystemIpxeArtifactCacheStrategy `json:"cacheStrategy"`
+}

As per path instructions, db/pkg/db/model.MachineCapabilityType "type X string with (X).ToProto() cwssaws.X... are the reference for typed-string domain enums that round-trip with proto enum values."

Also applies to: 159-209

🤖 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 `@rest-api/db/pkg/db/model/operatingsystem.go` around lines 62 - 69, Refactor
OperatingSystemIpxeArtifact.CacheStrategy away from a bare string and the
package-level proto maps into a dedicated named CacheStrategy type that owns its
own ToProto and FromProto methods, matching the existing MachineCapabilityType
pattern. Update the enum constants in operatingSystem.go to be typed
CacheStrategy values, and move the proto round-trip logic currently embedded in
OperatingSystemIpxeArtifact.FromProto and ToProto onto the CacheStrategy type so
conversion stays localized and type-safe.

Source: Coding guidelines

🤖 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 `@rest-api/db/pkg/db/model/ipxetemplate.go`:
- Around line 198-217: GetAll handles an explicit empty IDs filter by returning
no rows, but it does not do the same for Names. Update IpxeTemplateSQLDAO.GetAll
to mirror the IDs check for filter.Names so a non-nil empty Names slice returns
an empty result set before building the query. Make sure the behavior stays
consistent with setQueryWithFilter and the existing early-return logic in
GetAll.

In `@rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go`:
- Around line 192-234: In IpxeTemplateSiteAssociationSQLDAO.GetAll, treat
explicit empty association filters as a no-match instead of ignoring them. Add
the same guard used by IpxeTemplateSQLDAO.GetAll so that when
filter.IpxeTemplateIDs or filter.SiteIDs is non-nil but has length 0, the method
short-circuits and returns no rows before building the query. Keep the existing
behavior for nil filters, and apply the check alongside the current query setup
in IpxeTemplateSiteAssociationSQLDAO.GetAll.

---

Nitpick comments:
In `@rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go`:
- Around line 17-33: The schema bootstrap in
testIpxeTemplateSiteAssociationSetupSchema duplicates the ipxe_template
unique-constraint drop/add logic already used in testIpxeTemplateSetupSchema;
extract that repeated ALTER TABLE sequence into a shared helper with a clear
name such as a constraint bootstrap helper, then call it from both test setup
functions so the ipxe_template_name_key definition stays consistent in one
place.

In `@rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go`:
- Around line 59-64: The composite uniqueness for the ipxe_template/site
association is currently only enforced in migration SQL and test setup, so it is
easy to miss when the model is reset elsewhere. Update
IpxeTemplateSiteAssociation’s BeforeCreateTable method to declare the
(ipxe_template_id, site_id) UNIQUE constraint alongside the existing ForeignKey
calls, so the invariant is defined with the model rather than only in
migrations.

In `@rest-api/db/pkg/db/model/operatingsystem.go`:
- Around line 129-132: The scope filter in GetAll is duplicating the iPXE type
list inline instead of reusing IsIPXEType, which risks drift if more iPXE
variants are added. Update the filtering logic in GetAll to use IsIPXEType as
the single source of truth for identifying iPXE OS types, and remove the
hardcoded []string{OperatingSystemTypeIPXE, OperatingSystemTypeTemplatedIPXE}
set so both call sites stay consistent.
- Around line 62-69: Refactor OperatingSystemIpxeArtifact.CacheStrategy away
from a bare string and the package-level proto maps into a dedicated named
CacheStrategy type that owns its own ToProto and FromProto methods, matching the
existing MachineCapabilityType pattern. Update the enum constants in
operatingSystem.go to be typed CacheStrategy values, and move the proto
round-trip logic currently embedded in OperatingSystemIpxeArtifact.FromProto and
ToProto onto the CacheStrategy type so conversion stays localized and type-safe.

In `@rest-api/db/pkg/migrations/20260623150000_ipxe_os_and_templates.go`:
- Around line 40-50: Remove the redundant name index from the ipxe template
migration: the IpxeTemplate model already makes name unique, so
tx.NewCreateTable() will create the implicit unique index for it. In the
migration logic around the IpxeTemplate table creation, keep only the
non-duplicate indexes (scope, created, updated) and drop the extra CREATE INDEX
on name to avoid unnecessary storage and write overhead.
🪄 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: c4daaa15-1006-44d3-9e1f-dcc689f770d6

📥 Commits

Reviewing files that changed from the base of the PR and between 2e55228 and 011d2a3.

⛔ Files ignored due to path filters (1)
  • rest-api/workflow-schema/schema/site-agent/workflows/v1/inventory.pb.go is excluded by !**/*.pb.go, !rest-api/**/*.pb.go
📒 Files selected for processing (9)
  • rest-api/db/pkg/db/model/ipxetemplate.go
  • rest-api/db/pkg/db/model/ipxetemplate_test.go
  • rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go
  • rest-api/db/pkg/db/model/ipxetemplatesiteassociation_test.go
  • rest-api/db/pkg/db/model/operatingsystem.go
  • rest-api/db/pkg/db/model/operatingsystem_ipxe_test.go
  • rest-api/db/pkg/db/model/operatingsystemsiteassociation.go
  • rest-api/db/pkg/migrations/20260623150000_ipxe_os_and_templates.go
  • rest-api/workflow-schema/site-agent/workflows/v1/inventory.proto

Comment thread rest-api/db/pkg/db/model/ipxetemplate.go
Comment thread rest-api/db/pkg/db/model/ipxetemplatesiteassociation.go

@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 @pbreton

Deleted *time.Time `bun:"deleted,soft_delete"`
CreatedBy uuid.UUID `bun:"created_by,type:uuid,notnull"`
// ControllerState mirrors the tenant state reported by nico-core for this OS at this site.
ControllerState *string `bun:"controller_state"`

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.

To check whether Status would be sufficient.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OS like 'machine' has bi-directional updates: the source of truth changes based on the direction. Going single state would not allow to detect drift/desync and intent vs reported state if we have a need for it.

Comment thread rest-api/db/pkg/db/model/ipxetemplate.go Outdated
Address review feedback on the iPXE template DAOs:

- GetAll now treats a non-nil but empty filter slice as a no-match and
  short-circuits before building the query, for both IpxeTemplate (Names)
  and IpxeTemplateSiteAssociation (IpxeTemplateIDs / SiteIDs), matching the
  existing IDs guard.
- Rename IpxeTemplateFilterInput.IDs to IpxeTemplateIDs for consistency with
  the other filter structs.

Adds table cases covering the empty-slice early returns.
@pbreton
pbreton merged commit 830951c into NVIDIA:main Jul 7, 2026
117 checks passed
pbreton added a commit that referenced this pull request Jul 15, 2026
…ies (#3232)

Adds the synchronization layer for the Templated iPXE Operating System
feature: the cloud-side inbound reconcile plus the site-agent /
site-workflow inventory collectors that keep Operating System
definitions and iPXE templates consistent between on-site NICo Core and
NICo REST.
Additive workflow/collector wiring only; no schema or API changes.

Site-agent collectors discover Operating Systems and iPXE templates
on-site and publish them as inventory; cloud inventory workflows
reconcile that inventory into the DB.

## Related issues
- follow-up to #3160

## Type of Change
- [x] **Add** - New feature or capability

## Breaking Changes
- [ ] **This PR contains breaking changes**

## Testing
- [x] Unit tests added/updated

Signed-off-by: Patrice Breton <pbreton@nvidia.com>
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