Skip to content

OSAC-1347: Add BareMetalInstance reconciler for bare-metal-fulfillment-operator#703

Draft
carbonin wants to merge 2 commits into
osac-project:mainfrom
carbonin:bmf-controller
Draft

OSAC-1347: Add BareMetalInstance reconciler for bare-metal-fulfillment-operator#703
carbonin wants to merge 2 commits into
osac-project:mainfrom
carbonin:bmf-controller

Conversation

@carbonin

@carbonin carbonin commented Jun 15, 2026

Copy link
Copy Markdown

Add a reconciler that watches BareMetalInstance objects in the fulfillment service database and creates corresponding BareMetalInstance CRs in hub Kubernetes clusters, following the same pattern as the existing ComputeInstance reconciler.

The reconciler handles the full lifecycle:

  • Finalizer management to prevent premature deletion
  • Hub selection and caching
  • Catalog item resolution to obtain the template ID
  • BareMetalInstance CR creation and patching in hub clusters
  • Run strategy mapping (ALWAYS/HALTED to poweredOn bool)
  • User data Secret creation with owner references
  • Deletion flow with decommissioned hub handling

The template ID is passed through from the catalog item's template reference, matching the ComputeInstance pattern where the admin sets a meaningful template identifier (e.g. osac.templates.gpu_host) that flows through to the CRD and ultimately to AAP extra vars.

Also registers the bare-metal-fulfillment-operator CRD types in the hub scheme so the controller-runtime client can work with them.

Test Steps

Prerequisites

Tested on a locally deployed osac instance:

  1. Deployed the new fulfillment-service image to fulfillment-controller, fulfillment-grpc-server, and fulfillment-rest-gateway deployments
  2. Installed the baremetalinstances.osac.openshift.io CRD (from bare-metal-fulfillment-operator)
  3. Added baremetalinstances and baremetalinstances/status permissions to the hub-access Role (patch to osac-installer included)
  4. Registered a hub with a long-lived service account token kubeconfig

E2E: Create flow

  1. Created a BareMetalInstanceTemplate via the private API with a meaningful ID (osac.templates.gpu_host)
  2. Created a BareMetalInstanceCatalogItem referencing the template by ID, with published: true
  3. Created a BareMetalInstance via the private API referencing the catalog item, with:
    - Valid SSH key
    - Cloud-init user data (#cloud-config\npackages:\n - curl)
    - run_strategy: BARE_METAL_INSTANCE_RUN_STRATEGY_HALTED

Verified:

  • Reconciler added the fulfillment-controller finalizer to the database object
  • Reconciler selected a hub and saved it in status.hub
  • Reconciler set status.state to BARE_METAL_INSTANCE_STATE_PROVISIONING and initialized all 6 condition types
  • A BareMetalInstance CR was created in the hub namespace with:
    • spec.templateID: osac.templates.gpu_host (passed through from catalog item's template reference)
    • spec.poweredOn: false (mapped from HALTED run strategy)
    • Label osac.openshift.io/baremetalinstance-uuid set to the fulfillment API ID
    • Annotation osac.openshift.io/tenant: shared
  • A user data Secret was created with:
    • Owner reference to the BareMetalInstance CR
    • Label matching the fulfillment API ID
    • Correct cloud-init content

E2E: Update flow

  1. Updated run_strategy from HALTED to ALWAYS via the private API using a field mask

Verified:

  • The CR's spec.poweredOn changed from false to true

E2E: Delete flow

  1. Deleted the BareMetalInstance via the private API

Verified:

  • The BareMetalInstance CR was deleted from the hub cluster
  • The user data Secret was garbage-collected (owner reference)
  • The reconciler removed its finalizer after confirming the CR was gone
  • The instance was archived (Get returns NotFound)

Resolves https://redhat.atlassian.net/browse/OSAC-1347
Depends on #683

Assisted-by: Claude Code noreply@anthropic.com

Summary by CodeRabbit

  • New Features
    • Added bare metal instance reconciliation to provision, update, and delete instances across hub clusters, including status/condition management, finalizer handling, and hub-side resource synchronization.
  • Chores
    • Updated module dependencies, including adding the bare metal fulfillment operator and refreshing related indirect versions.
    • Extended Kubernetes scheme support for the fulfillment operator types.
    • Added a new Kubernetes label for bare metal instance identifiers.
  • Tests
    • Introduced a new Ginkgo/Gomega test suite with extensive unit coverage for reconciliation behavior.

@openshift-ci-robot

openshift-ci-robot commented Jun 15, 2026

Copy link
Copy Markdown

@carbonin: This pull request references OSAC-1347 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Add a reconciler that watches BareMetalInstance objects in the fulfillment service database and creates corresponding BareMetalInstance CRs in hub Kubernetes clusters, following the same pattern as the existing ComputeInstance reconciler.

The reconciler handles the full lifecycle:

  • Finalizer management to prevent premature deletion
  • Hub selection and caching
  • Catalog item resolution to obtain the template ID
  • BareMetalInstance CR creation and patching in hub clusters
  • Run strategy mapping (ALWAYS/HALTED to poweredOn bool)
  • User data Secret creation with owner references
  • Deletion flow with decommissioned hub handling

The template ID is passed through from the catalog item's template reference, matching the ComputeInstance pattern where the admin sets a meaningful template identifier (e.g. osac.templates.gpu_host) that flows through to the CRD and ultimately to AAP extra vars.

Also registers the bare-metal-fulfillment-operator CRD types in the hub scheme so the controller-runtime client can work with them.

Test Steps

Prerequisites

Tested on a locally deployed osac instance:

  1. Deployed the new fulfillment-service image to fulfillment-controller, fulfillment-grpc-server, and fulfillment-rest-gateway deployments
  2. Installed the baremetalinstances.osac.openshift.io CRD (from bare-metal-fulfillment-operator)
  3. Added baremetalinstances and baremetalinstances/status permissions to the hub-access Role (patch to osac-installer included)
  4. Registered a hub with a long-lived service account token kubeconfig

E2E: Create flow

  1. Created a BareMetalInstanceTemplate via the private API with a meaningful ID (osac.templates.gpu_host)
  2. Created a BareMetalInstanceCatalogItem referencing the template by ID, with published: true
  3. Created a BareMetalInstance via the private API referencing the catalog item, with:
  • Valid SSH key
  • Cloud-init user data (#cloud-config\npackages:\n - curl)
  • run_strategy: BARE_METAL_INSTANCE_RUN_STRATEGY_HALTED

Verified:

  • Reconciler added the fulfillment-controller finalizer to the database object
  • Reconciler selected a hub and saved it in status.hub
  • Reconciler set status.state to BARE_METAL_INSTANCE_STATE_PROVISIONING and initialized all 6 condition types
  • A BareMetalInstance CR was created in the hub namespace with:
    • spec.templateID: osac.templates.gpu_host (passed through from catalog item's template reference)
    • spec.poweredOn: false (mapped from HALTED run strategy)
    • Label osac.openshift.io/baremetalinstance-uuid set to the fulfillment API ID
    • Annotation osac.openshift.io/tenant: shared
  • A user data Secret was created with:
    • Owner reference to the BareMetalInstance CR
    • Label matching the fulfillment API ID
    • Correct cloud-init content

E2E: Update flow

  1. Updated run_strategy from HALTED to ALWAYS via the private API using a field mask

Verified:

  • The CR's spec.poweredOn changed from false to true

E2E: Delete flow

  1. Deleted the BareMetalInstance via the private API

Verified:

  • The BareMetalInstance CR was deleted from the hub cluster
  • The user data Secret was garbage-collected (owner reference)
  • The reconciler removed its finalizer after confirming the CR was gone
  • The instance was archived (Get returns NotFound)

Resolves https://redhat.atlassian.net/browse/OSAC-1347

Assisted-by: Claude Code noreply@anthropic.com

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jun 15, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: carbonin
Once this PR has been reviewed and has the lgtm label, please assign rgolangh for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@carbonin

carbonin commented Jun 15, 2026

Copy link
Copy Markdown
Author

Added a hold until #683 and the installer PR are merged.

@carbonin carbonin marked this pull request as draft June 15, 2026 16:15
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 5824ad54-1052-484a-a32b-afa9557604ac

📥 Commits

Reviewing files that changed from the base of the PR and between 8a2ec25 and 2944eb0.

📒 Files selected for processing (2)
  • internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
  • internal/controllers/baremetalinstance/baremetalinstance_reconciler_function_test.go
 __________________________________________
< Dollars to donuts, you didn't test this. >
 ------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

Walkthrough

Introduces a new BareMetalInstance controller reconciler that maps privatev1.BareMetalInstance desired state to hub-side bmfov1alpha1.BareMetalInstance Kubernetes CRs via gRPC. Adds the FunctionBuilder, hub scheme registration, a BareMetalInstanceUuid label constant, command wiring, dependency additions, and a Ginkgo unit test suite covering the update, delete, and user-data secret paths.

Changes

BareMetalInstance Reconciler Feature

Layer / File(s) Summary
Shared infrastructure: label constant and scheme registration
internal/kubernetes/labels/kubernetes_labels.go, internal/kubernetes/scheme/scheme.go
Adds BareMetalInstanceUuid label constant for hub-side CR UUID matching and registers bmfov1alpha1 CRD types into the hub runtime scheme via an additional AddToScheme call.
Dependency additions
go.mod
Adds github.com/osac-project/bare-metal-fulfillment-operator as a direct dependency and bumps indirect dependencies golang.org/x/crypto to v0.52.0 and github.com/go-openapi/jsonreference to v0.21.0.
FunctionBuilder, types, and reconcile control flow
internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
Defines FunctionBuilder, internal function/task types, the Build method wiring gRPC clients and protobuf mask calculator, and the run entrypoint routing to update or delete before calling bareMetalInstancesClient.Update.
Update path: provisioning, hub selection, CR create/patch, spec building, user-data secret
internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
Implements finalizer addition, status defaults, condition upsert, tenant validation, hub selection and recording, hub-side CR create or spec patch, catalog item resolution to template ID with runStrategy mapping, and user-data Secret creation with owner references.
Delete path: finalizer removal and hub-side CR deletion
internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
Implements deletion: removes finalizer when hub ID is absent or hub-side CR is missing, triggers K8s deletion when CR is not yet marked for deletion, and handles ErrHubNotFound.
Command wiring
internal/cmd/service/start/controller/start_controller_cmd.go
Wires the BareMetalInstance reconciler into the controller start command with gRPC connection, hub cache, event filter, health reporter, and goroutine launch with consistent completion logging.
Test suite: buildSpec, delete, ensureUserDataSecret
internal/controllers/baremetalinstance/baremetalinstance_suite_test.go, internal/controllers/baremetalinstance/baremetalinstance_reconciler_function_test.go
Adds Ginkgo suite bootstrap with package-level logger, test helpers (CR builders, fake catalog client, scheme setup), and unit tests covering catalog/runStrategy mapping, delete finalizer and hub-CR behaviors, and user-data Secret creation/idempotency/error paths.

Sequence Diagram(s)

sequenceDiagram
  participant Controller as Controller Command
  participant FunctionBuilder
  participant run as function.run
  participant hubCache
  participant hubK8sClient as Hub K8s Client
  participant catalogClient as Catalog Client
  participant bareMetalInstancesClient as gRPC BareMetalInstancesClient

  Controller->>FunctionBuilder: Build() → ReconcilerFunction
  Controller->>run: run(ctx, BareMetalInstance)
  run->>run: clone instance
  alt deletionTimestamp set
    run->>hubCache: getHub(hubID)
    run->>hubK8sClient: Get / Delete BareMetalInstance CR
    run->>run: removeFinalizer
  else provisioning / update
    run->>run: addFinalizer, setDefaults, validateTenant
    run->>hubCache: selectHub / getHub
    run->>hubK8sClient: List by UUID label
    alt CR not found
      run->>hubK8sClient: Create BareMetalInstance CR
    else CR exists
      run->>hubK8sClient: Patch Spec
    end
    run->>catalogClient: Get (template ID, runStrategy)
    run->>hubK8sClient: Create user-data Secret (if present)
  end
  run->>bareMetalInstancesClient: Update(ctx, instance, updateMask)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested reviewers

  • tzumainn
  • eranco74

Poem

⚙️ A bare metal host awaits its fate,
A reconciler wakes to orchestrate.
gRPC calls and hub CRs align,
Finalizers guard each deletion sign.
🔐 Secrets owned, conditions set with care —
No unauthorized instance shall dare. 🛡️


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error Logging exposes instance IDs and catalog item IDs in debug logs, warn logs, and error messages, which are sensitive customer data identifiers. Remove or sanitize instance ID logging from lines 271, 285, 368; sanitize catalog item ID from line 440 error message; avoid logging database identifiers that identify customer resources.
✅ Passed checks (10 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
No-Hardcoded-Secrets ✅ Passed No hardcoded secrets, API keys, tokens, passwords, private keys, or credentials found in PR changes. Sensitive data (SSH keys, user data) properly handled via Kubernetes Secrets, not hardcoded.
No-Weak-Crypto ✅ Passed No weak cryptographic algorithms (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB), custom crypto implementations, or non-constant-time secret comparisons found. Crypto imports limited to standard x509 ce...
No-Injection-Vectors ✅ Passed No injection vectors found. Code uses safe Go patterns: json.Marshal (not yaml.Load), no shell execution, no SQL concatenation, no eval/exec, proper protobuf field access, and Kubernetes Secret for...
Container-Privileges ✅ Passed No container/K8s manifests modified; PR contains only Go source code for a BareMetalInstance reconciler controller.
Ai-Attribution ✅ Passed AI tool use (Claude Code) is properly attributed via "Assisted-by" trailer in both PR description and commit message, with no misuse of Co-Authored-By.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: adding a BareMetalInstance reconciler for the bare-metal-fulfillment-operator integration.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

CodeRabbit can generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

@carbonin

Copy link
Copy Markdown
Author

Actually leaving this as a draft until the dependencies are merged at least

@carbonin

Copy link
Copy Markdown
Author

Installer PR osac-project/osac-installer#275

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@go.mod`:
- Line 34: Update the golang.org/x/crypto dependency from v0.51.0 to v0.52.0 in
the go.mod file to address four published CVEs affecting the current version:
GO-2026-5013 (SSH AES-GCM decoder panic), GO-2026-5019 (FIDO/U2F security key
bypass), GO-2026-5021 (SSH knownhosts revoked status bypass), and GO-2026-5018
(RSA/DSA key DoS). Change the version number on the golang.org/x/crypto
dependency line from v0.51.0 to v0.52.0.

In
`@internal/controllers/baremetalinstance/baremetalinstance_reconciler_function_test.go`:
- Around line 113-115: The test file
baremetalinstance_reconciler_function_test.go has formatting issues detected by
gofmt that need to be corrected. Run gofmt on the entire test file to
automatically fix all formatting drift and ensure it conforms to Go formatting
standards. This will resolve the CI/lint failures related to code formatting.

In
`@internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go`:
- Around line 55-60: The file
internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
is not properly formatted according to Go standards and requires gofmt to be
applied. Run gofmt on this file to automatically fix all formatting issues,
which will ensure the code adheres to the standard Go formatting conventions and
prevent CI/lint failures.
🪄 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: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 4ab76326-93ab-4d58-aa20-8a1e6e8521d3

📥 Commits

Reviewing files that changed from the base of the PR and between e0370c3 and 42c51fa.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • go.mod
  • internal/cmd/service/start/controller/start_controller_cmd.go
  • internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
  • internal/controllers/baremetalinstance/baremetalinstance_reconciler_function_test.go
  • internal/controllers/baremetalinstance/baremetalinstance_suite_test.go
  • internal/kubernetes/labels/kubernetes_labels.go
  • internal/kubernetes/scheme/scheme.go

Comment thread go.mod Outdated
Comment thread internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go Outdated
Comment on lines +447 to +448
poweredOn := true
spec.PoweredOn = &poweredOn

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.

Suggested change
poweredOn := true
spec.PoweredOn = &poweredOn
spec.PoweredOn = new(true)

nit: this new thing from go 1.26 should do the trick

@DanNiESh

DanNiESh commented Jun 15, 2026

Copy link
Copy Markdown

I think there are a few gaps in how this reconciler creates the BareMetalInstance CR, comparing with existing bare-metal-fulfillment-operator:

  • spec.hostType is not set. It is a required field to search for a matching host.
  • spec.templateParameters is not set. The reconciler resolves templateID from the catalog item, but doesn't pass through any template parameters.
  • spec.poweredOn: There's an in-progress PR in bare-metal-fulfillment-operator that replaces the PoweredOn bool with a RunStrategy enum (Always/Halted/""). The mapping should be updated to set spec.runStrategy once that PR is merged.
  • spec.selector.hostSelector is missing. The BareMetalPool controller in bare-metal-fulfillment-operator always sets {managedBy: "osac", provisionState: "available"} as defaults on the selector when creating the BMI CR. If the CR arrives at the bare-metal-fulfillment-operator without managedBy/provisionState in the selector, the baremetalinstance controller FindFreeHost call won't filter correctly.

@carbonin

Copy link
Copy Markdown
Author
  • spec.hostType is not set. It is a required field to search for a matching host.
  • spec.templateParameters is not set. The reconciler resolves templateID from the catalog item, but doesn't pass through any template parameters.

@adriengentil where do you feel like these should come from? We don't have any template overrides defined in the API, right?
Also we decided hostType would be "hardcoded" somewhere/somehow until we get inventory exposed I think?

Thanks, I'll keep an eye on this PR and update when it merges.

  • spec.selector.hostSelector is missing. The BareMetalPool controller in bare-metal-fulfillment-operator always sets {managedBy: "osac", provisionState: "available"} as defaults on the selector when creating the BMI CR. If the CR arrives at the bare-metal-fulfillment-operator without managedBy/provisionState in the selector, the baremetalinstance controller FindFreeHost call won't filter correctly.

This feels like an implementation detail of the baremetal-fulfilment-operator. I don't think fulfillment-service should know these kinds of details, does it make sense for these two labels to be a sensible default for a new BareMetalInstance without any other labels?

@tzumainn

Copy link
Copy Markdown
Contributor
  • spec.selector.hostSelector is missing. The BareMetalPool controller in bare-metal-fulfillment-operator always sets {managedBy: "osac", provisionState: "available"} as defaults on the selector when creating the BMI CR. If the CR arrives at the bare-metal-fulfillment-operator without managedBy/provisionState in the selector, the baremetalinstance controller FindFreeHost call won't filter correctly.

This feels like an implementation detail of the baremetal-fulfilment-operator. I don't think fulfillment-service should know these kinds of details, does it make sense for these two labels to be a sensible default for a new BareMetalInstance without any other labels?

Yeah, that makes sense. I'll open up an issue to take care of it from the baremetal-fulfillment-operator side.

…t-operator

Add a reconciler that watches BareMetalInstance objects in the
fulfillment service database and creates corresponding BareMetalInstance
CRs in hub Kubernetes clusters, following the same pattern as the
existing ComputeInstance reconciler.

The reconciler handles the full lifecycle:
- Finalizer management to prevent premature deletion
- Hub selection and caching
- Catalog item resolution to obtain the template ID
- BareMetalInstance CR creation and patching in hub clusters
- Run strategy mapping (ALWAYS/HALTED to poweredOn bool)
- User data Secret creation with owner references
- Deletion flow with decommissioned hub handling

The template ID is passed through from the catalog item's template
reference, matching the ComputeInstance pattern where the admin sets a
meaningful template identifier (e.g. osac.templates.gpu_host) that flows
through to the CRD and ultimately to AAP extra vars.

Also registers the bare-metal-fulfillment-operator CRD types in the hub
scheme so the controller-runtime client can work with them.

Resolves https://redhat.atlassian.net/browse/OSAC-1347

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Nick Carboni <ncarboni@redhat.com>
@carbonin carbonin force-pushed the bmf-controller branch 2 times, most recently from ba0d5e0 to 8a2ec25 Compare June 16, 2026 15:22
@carbonin

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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
`@internal/controllers/baremetalinstance/baremetalinstance_reconciler_function_test.go`:
- Around line 511-512: The NestedMap call in the test ignores both the found and
err return values, then directly accesses stringData[userDataSecretKey], which
will panic if stringData is nil when the field is missing or malformed. Check
both the found and err return values from the unstructured.NestedMap call and
add appropriate assertions (such as Expect(found).To(BeTrue()) and
Expect(err).NotTo(HaveOccurred())) before attempting to access
stringData[userDataSecretKey] to ensure the test fails with a clear error
message rather than panicking.

In
`@internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go`:
- Around line 173-175: The user-data secret handling currently only creates
secrets and ignores updates, and doesn't clean up removed secrets. The logic at
lines 173-175 only sets the secret name when user data is present, leaving stale
secrets behind when user data is removed. Fix this by: (1) updating the secret
creation logic around lines 480-520 to use create-or-patch semantics instead of
returning success on AlreadyExists, so that changes to spec.userData properly
update the existing Secret, and (2) adjusting lines 173-175 to always set the
secret name (regardless of whether current user data is present) so it can be
tracked for cleanup, and adding separate logic to delete the secret when user
data is removed from the spec.
- Around line 44-46: Remove the hardcoded `defaultHostType` constant and update
the `buildSpec()` function to resolve the host type from actual data sources.
Instead of always using `"default"`, derive the host type from the template
proto (once it's modeled) or from the catalog item metadata that is already
being fetched. Add validation to ensure the resolved host type exists in the
hub's inventory before assigning it to HostType in the spec. If the host type
cannot be resolved or does not exist on the hub, fail fast and return an error
rather than emitting an unschedulable CR with a placeholder value.
🪄 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: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: ccd4e52e-021f-4f74-957c-9e3c414e006f

📥 Commits

Reviewing files that changed from the base of the PR and between 42c51fa and 8a2ec25.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • go.mod
  • internal/cmd/service/start/controller/start_controller_cmd.go
  • internal/controllers/baremetalinstance/baremetalinstance_reconciler_function.go
  • internal/controllers/baremetalinstance/baremetalinstance_reconciler_function_test.go
  • internal/controllers/baremetalinstance/baremetalinstance_suite_test.go
  • internal/kubernetes/labels/kubernetes_labels.go
  • internal/kubernetes/scheme/scheme.go

Set HostType to a hardcoded "default" placeholder until host type is
modeled in the BareMetalInstanceTemplate proto.

Build TemplateParameters as a JSON object containing sshKey (the SSH
public key value) and userDataSecret (the name of the user data Secret
in the hub namespace) when present. Keys use camelCase to match the
existing AAP template parameter convention (imageURL,
provisioningNetwork, etc.). The AAP provisioning role parses
templateParameters as JSON to access these values.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Nick Carboni <ncarboni@redhat.com>
@carbonin

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Action performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants