Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.

MGMT-23769: Provide up front validation and handling of template prov… - #414

Merged
openshift-merge-bot[bot] merged 3 commits into
osac-project:mainfrom
DakCrowder:compute-instance-spec-defaults
Apr 28, 2026
Merged

openshift-merge-bot[bot] merged 3 commits into
osac-project:mainfrom
DakCrowder:compute-instance-spec-defaults

Conversation

@DakCrowder

@DakCrowder DakCrowder commented Apr 15, 2026 •

Copy link
Copy Markdown
Contributor

Adds validation and initialization of compute instances using fetched template spec default values.

The gist of this is we fetch the template (was already occurring), but the template we get back now includes spec defaults. We take the compute instance request body, populate fields on the request body from the spec defaults (such as cpu cores, memory etc.) and then validate the combined payload. The result is users can get additional feedback on fields they must define if the template doesn't define them, and we populate the initial values from the spec defaults if the user doesn't provide specific values.

For example, if we had a template that had NO defaults defined, the user can now see they need to define fields such as cores, memory etc. at creation time rather than having to debug why their VM won't spin up later on.

osac create computeinstance --name test --template test-no-defaults
Error: failed to create compute instance: rpc error: code = InvalidArgument desc = the following required spec fields are missing: boot_disk, cores, image, memory_gib, run_strategy

Additionally if users specify a template with the defaults defined those defaults will be used to populate the computinstance.

# Populates all values from the template defined defaults
osac create computeinstance --name test --template osac.templates.ocp_virt_vm

User values always have precedence - so in a case like the following the user passed cores and memory will override the template default, while the other values will be sourced from the template.

# Populates cores and memory from the passed user value, and the rest of the values from template defined defaults
osac create computeinstance --name test --template osac.templates.ocp_virt_vm --cores 4 --memory-gib 16

Additionally if a template does NOT define a value (e.g. lets say cores is NOT specified in the default spec values), the user then must provide that value.

# If a template does not define cores and a user does NOT pass them we fail
osac create computeinstance --name test --template no-cores-defined-in-default-spec
Error: failed to create compute instance: rpc error: code = InvalidArgument desc = the following required spec fields are missing: cores
# If a template does not define cores and a user does pass them it succeeds
osac create computeinstance --name test --template no-cores-defined-in-default-spec --cores 4

Requires osac-project/osac-aap#246 to fetch the default fields from templates

Summary by CodeRabbit

  • New Features

    • Templates can include spec defaults (cores, memory, image, boot disk, run strategy) that are applied when creating instances.
  • Improvements

    • Create/update flow applies template defaults and validates required fields; user-provided spec values take precedence. Validation aggregates missing-field errors and rejects invalid run strategy values.
  • Tests

    • Added unit and integration tests covering defaulting, validation, persistence semantics, and error messages.

@openshift-ci-robot

openshift-ci-robot commented Apr 15, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

…ided spec default values for computeinstances

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-robot

openshift-ci-robot commented Apr 15, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

…ided spec default values for computeinstances

Summary by CodeRabbit

  • New Features

  • Compute instance templates can now define default specifications (CPU cores, memory, image, boot disk, and run strategy). These defaults are applied when creating instances without explicitly setting these fields. User-provided values always override template defaults.

  • Improvements

  • Enhanced validation ensures all required configuration is present after applying template defaults, with clear error messages listing any missing fields.

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.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Public and private protos add ComputeInstanceTemplateSpecDefaults and a spec_defaults field on ComputeInstanceTemplate. A new utils file provides ApplySpecDefaults and ValidateRequiredSpecFields (including run-strategy validation). The private compute instances server refactors template handling: it fetches/validates templates, applies template-parameter defaults, and applies template spec defaults before validating required fields; Create/Update flows updated accordingly. Tests and integration tests were added/updated to cover defaulting, validation, persistence semantics, and the test DB readiness timeout was increased to 30s.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • akshaynadkarni
  • omer-vishlitzky
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is truncated and incomplete, ending with an ellipsis ('prov…'). While it clearly references the Jira ticket (MGMT-23769) and hints at the main feature (template provisioning/validation), the truncation makes it vague about the exact scope and prevents readers from understanding the complete primary change. Complete the title to clearly state the full change: 'MGMT-23769: Provide up front validation and handling of template spec defaults' or similar, ensuring the title is not truncated and fully conveys the feature scope.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ 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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/servers/private_compute_instances_server.go (1)

200-205: ⚠️ Potential issue | 🟠 Major

Apply spec_defaults when template changes during Update to match Create behavior.

The Update method validates the new template but does not apply its spec_defaults, unlike the Create method which explicitly calls ApplySpecDefaults. When a user updates spec.template to a different template, the new template's defaults are silently ignored. Since ApplySpecDefaults only fills unset fields (preserving any user-provided values), applying defaults on template change would be safe and consistent with Create semantics. Without this, updates to a template could leave required fields missing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/servers/private_compute_instances_server.go` around lines 200 - 205,
In Update, when detecting template changes via hasMaskPrefix(mask,
"spec.template", "spec.template_parameters") and after calling
s.fetchAndValidateTemplate(ctx, request.GetObject()), call ApplySpecDefaults on
the incoming object (the same object passed to fetchAndValidateTemplate /
request.GetObject()) to populate any unset fields from the new template; ensure
you handle and return any error from ApplySpecDefaults consistently (like the
existing error path) so Update matches Create's behavior of applying spec
defaults when the template changes.
🧹 Nitpick comments (2)
internal/utils/spec_defaults.go (1)

28-30: Consider documenting the source of valid run strategies.

The comment mentions these values match the Kubernetes ComputeInstance CRD. Consider adding a reference to where these values are defined in the CRD or noting that this list must be kept in sync with the CRD.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/utils/spec_defaults.go` around lines 28 - 30, Update the comment for
validRunStrategies to reference the authoritative source and maintenance note:
state exactly which Kubernetes ComputeInstance CRD (e.g., its API group/version
or repo/manifest) defines the allowed values and add a concise "must be kept in
sync" note so future maintainers know to update validRunStrategies when the CRD
changes; mention the symbol validRunStrategies and the Kubernetes
ComputeInstance CRD in the comment to make the linkage explicit.
internal/servers/private_compute_instances_server_test.go (1)

702-706: Inconsistent DAO builder configuration.

These inline template DAOs include SetAttributionLogic(attribution) while the createTemplate helper (Line 247-251) does not set attribution logic. This inconsistency could mask issues or cause test failures if attribution logic behavior changes.

Consider aligning the DAO construction to be consistent, either always including or always omitting SetAttributionLogic.

Also applies to: 740-744, 780-784

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/servers/private_compute_instances_server_test.go` around lines 702 -
706, The test DAOs are built inconsistently: some inline
NewGenericDAO[*privatev1.ComputeInstanceTemplate]() chains include
SetAttributionLogic(attribution) while the createTemplate helper does not;
update the createTemplate helper to include SetAttributionLogic(attribution) so
all template DAOs use the same attribution logic (or alternatively remove
SetAttributionLogic from the inline builders to match createTemplate) — modify
the createTemplate helper (and mirror changes to any other helper used for
templates) or the inline NewGenericDAO[...]() chains (the locations using
SetAttributionLogic(attribution) in the ComputeInstanceTemplate DAO builders) to
make the configuration consistent across tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/servers/private_compute_instances_server.go`:
- Around line 200-205: In Update, when detecting template changes via
hasMaskPrefix(mask, "spec.template", "spec.template_parameters") and after
calling s.fetchAndValidateTemplate(ctx, request.GetObject()), call
ApplySpecDefaults on the incoming object (the same object passed to
fetchAndValidateTemplate / request.GetObject()) to populate any unset fields
from the new template; ensure you handle and return any error from
ApplySpecDefaults consistently (like the existing error path) so Update matches
Create's behavior of applying spec defaults when the template changes.

---

Nitpick comments:
In `@internal/servers/private_compute_instances_server_test.go`:
- Around line 702-706: The test DAOs are built inconsistently: some inline
NewGenericDAO[*privatev1.ComputeInstanceTemplate]() chains include
SetAttributionLogic(attribution) while the createTemplate helper does not;
update the createTemplate helper to include SetAttributionLogic(attribution) so
all template DAOs use the same attribution logic (or alternatively remove
SetAttributionLogic from the inline builders to match createTemplate) — modify
the createTemplate helper (and mirror changes to any other helper used for
templates) or the inline NewGenericDAO[...]() chains (the locations using
SetAttributionLogic(attribution) in the ComputeInstanceTemplate DAO builders) to
make the configuration consistent across tests.

In `@internal/utils/spec_defaults.go`:
- Around line 28-30: Update the comment for validRunStrategies to reference the
authoritative source and maintenance note: state exactly which Kubernetes
ComputeInstance CRD (e.g., its API group/version or repo/manifest) defines the
allowed values and add a concise "must be kept in sync" note so future
maintainers know to update validRunStrategies when the CRD changes; mention the
symbol validRunStrategies and the Kubernetes ComputeInstance CRD in the comment
to make the linkage explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bb53957c-425e-4f59-a0c3-e7ba1169c0a0

📥 Commits

Reviewing files that changed from the base of the PR and between 2e9b8e8 and d166ccf.

⛔ Files ignored due to path filters (4)
  • internal/api/osac/private/v1/compute_instance_template_type.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/private/v1/compute_instance_template_type_protoopaque.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/public/v1/compute_instance_template_type.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/public/v1/compute_instance_template_type_protoopaque.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (8)
  • internal/servers/compute_instances_server_test.go
  • internal/servers/private_compute_instances_server.go
  • internal/servers/private_compute_instances_server_test.go
  • internal/testing/database.go
  • internal/utils/spec_defaults.go
  • internal/utils/spec_defaults_test.go
  • proto/private/osac/private/v1/compute_instance_template_type.proto
  • proto/public/osac/public/v1/compute_instance_template_type.proto

@DakCrowder
DakCrowder force-pushed the compute-instance-spec-defaults branch from d166ccf to 761ae48 Compare April 15, 2026 19:15
@openshift-ci-robot

openshift-ci-robot commented Apr 15, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

…ided spec default values for computeinstances

Summary by CodeRabbit

  • New Features

  • Compute instance templates can now define default specifications (CPU cores, memory, image, boot disk, and run strategy). These defaults are applied when creating instances without explicitly setting those fields; user-provided values always take precedence.

  • Improvements

  • Creation/update now applies template defaults and enforces required fields after defaults are applied, returning clear errors that list any missing fields. Public-to-private mapping preserves user overrides while filling in template defaults.

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.

@DakCrowder
DakCrowder force-pushed the compute-instance-spec-defaults branch 2 times, most recently from 8de0540 to 36d3083 Compare April 15, 2026 22:13
@openshift-ci-robot

openshift-ci-robot commented Apr 15, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

…ided spec default values for computeinstances

Summary by CodeRabbit

  • New Features

  • Templates can include spec defaults (CPU, memory, image, boot disk, run strategy) that are applied when creating instances.

  • Improvements

  • Creation/update now applies template defaults during validation; user-provided fields always win and are preserved in stored specs. Validation errors list all missing required fields.

  • Tests

  • Added behavioral and unit tests covering defaulting, validation, persistence semantics, and error messages.

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.

@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: 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 `@internal/servers/private_compute_instances_server.go`:
- Around line 198-214: Currently the code fetches/validates the template from
the sparse request before merging the current object, causing validation to use
request.template_parameters instead of the effective post-update spec; change
the order so you first load the current instance (fetchCurrentInstance) and call
mergeSpecFromMask(current.GetSpec(), request.GetSpec(), mask) to produce
mergedSpec, then derive/resolve the template from that mergedSpec (replace
fetchAndValidateTemplate(ctx, request.GetObject()) with a fetch/validate that
takes mergedSpec or its template reference), and finally call
validateSpecWithDefaults(mergedSpec, template); apply the same reorder to the
analogous block later in the file that mirrors this logic (the code using
hasMaskPrefix, fetchAndValidateTemplate, mergeSpecFromMask, and
validateSpecWithDefaults).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a280fcf-ae30-44f9-a2da-5e49cd7a7f4b

📥 Commits

Reviewing files that changed from the base of the PR and between 761ae48 and 36d3083.

⛔ Files ignored due to path filters (4)
  • internal/api/osac/private/v1/compute_instance_template_type.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/private/v1/compute_instance_template_type_protoopaque.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/public/v1/compute_instance_template_type.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/public/v1/compute_instance_template_type_protoopaque.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (8)
  • internal/servers/compute_instances_server_test.go
  • internal/servers/private_compute_instances_server.go
  • internal/servers/private_compute_instances_server_test.go
  • internal/testing/database.go
  • internal/utils/spec_defaults.go
  • internal/utils/spec_defaults_test.go
  • proto/private/osac/private/v1/compute_instance_template_type.proto
  • proto/public/osac/public/v1/compute_instance_template_type.proto
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/testing/database.go
  • internal/servers/compute_instances_server_test.go
  • internal/utils/spec_defaults_test.go
  • proto/private/osac/private/v1/compute_instance_template_type.proto

Comment thread internal/servers/private_compute_instances_server.go Outdated
@DakCrowder
DakCrowder force-pushed the compute-instance-spec-defaults branch from 00b2f5d to 1185cb2 Compare April 16, 2026 13:12
@openshift-ci-robot

openshift-ci-robot commented Apr 16, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

…ided spec default values for computeinstances

Summary by CodeRabbit

  • New Features

  • Templates can include spec defaults (CPU, memory, image, boot disk, run strategy) applied when creating instances.

  • Improvements

  • Creation/update now applies template defaults during validation; user-provided fields take precedence and are preserved. Validation reports all missing required fields and rejects invalid run strategy values.

  • Tests

  • Added unit and integration tests for defaulting, validation, persistence semantics, and error messages.

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.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/servers/private_compute_instances_server.go (1)

264-275: ⚠️ Potential issue | 🟠 Major

Preserve InvalidArgument for missing templates.

Lines 345-353 and 383-391 already translate *dao.ErrNotFound from GenericDAO.Get().Do(ctx) into InvalidArgument, but this helper maps every lookup error to Internal. A missing template will therefore surface as a 500 instead of a bad user reference. Handle *dao.ErrNotFound here before falling back to the generic internal error.

🐛 Proposed fix
  getTemplateResponse, err := s.templatesDao.Get().
  	SetId(templateID).
  	Do(ctx)
  if err != nil {
+ 	var notFoundErr *dao.ErrNotFound
+ 	if errors.As(err, &notFoundErr) {
+ 		return nil, grpcstatus.Errorf(
+ 			grpccodes.InvalidArgument,
+ 			"template '%s' does not exist",
+ 			templateID,
+ 		)
+ 	}
  	s.logger.ErrorContext(
  		ctx,
  		"Template retrieval failed",
  		slog.String("template_id", templateID),
  		slog.Any("error", err),
  	)
  	return nil, grpcstatus.Errorf(
  		grpccodes.Internal,
  		"failed to retrieve template '%s'",
  		templateID,
  	)
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/servers/private_compute_instances_server.go` around lines 264 - 275,
The current error handling in the template retrieval block maps all errors to
Internal; instead detect whether err is a *dao.ErrNotFound and, if so, log and
return grpcstatus.Errorf(grpccodes.InvalidArgument, "template '%s' not found",
templateID) (preserving the s.logger.ErrorContext call and its fields),
otherwise keep the existing Internal log+grpcstatus.Errorf behavior; reference
dao.ErrNotFound, s.logger.ErrorContext, templateID, grpcstatus.Errorf and
grpccodes.Internal/InvalidArgument and add an import for the dao package if not
already present.
♻️ Duplicate comments (1)
internal/servers/private_compute_instances_server.go (1)

198-205: ⚠️ Potential issue | 🟠 Major

Validate the effective post-update spec before calling generic.Update.

A sparse patch that only touches spec.template_parameters reaches Line 233 with no spec.template, so this path rejects a valid update with "template ID is mandatory". It also still skips validateSpecWithDefaults, so a spec.template change can swap to a template with no spec_defaults and persist an instance that no longer has all required spec fields. Fetch the current object, merge the masked spec first, then resolve the effective template and validate that merged spec once.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/servers/private_compute_instances_server.go` around lines 198 - 205,
The current flow validates only when mask includes spec.template or
spec.template_parameters and then calls s.generic.Update, which can persist an
invalid effective spec; instead, fetch the current object (via existing fetch
method used elsewhere), merge the incoming masked spec into the current object's
spec before calling fetchAndValidateTemplate/validateSpecWithDefaults to resolve
the effective template and apply defaults, ensure the merged/validated spec
passes validation, and only then call s.generic.Update with the original request
(or with the merged spec applied) so updates that only touch template_parameters
or remove template-required defaults are correctly validated; use hasMaskPrefix,
fetchAndValidateTemplate, validateSpecWithDefaults and s.generic.Update as the
reference points when implementing this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/utils/spec_defaults.go`:
- Around line 28-30: validRunStrategies currently only contains "Always" and
"Halted" but the code path that validates run strategies (referenced around the
validation that errors for invalid run strategies) is intended to match
KubeVirt's VirtualMachine CRD which actually accepts "Always", "RerunOnFailure",
"Once", "Manual", and "Halted"; update validRunStrategies to include all five
values ("Always","RerunOnFailure","Once","Manual","Halted") so upstream inputs
are accepted, and if you intentionally want to restrict values instead, change
the top comment above validRunStrategies and the validation error message that
references this check to state this is a product-specific restriction rather
than a CRD match (reference symbols: validRunStrategies and the run-strategy
validation code that produces the error).

---

Outside diff comments:
In `@internal/servers/private_compute_instances_server.go`:
- Around line 264-275: The current error handling in the template retrieval
block maps all errors to Internal; instead detect whether err is a
*dao.ErrNotFound and, if so, log and return
grpcstatus.Errorf(grpccodes.InvalidArgument, "template '%s' not found",
templateID) (preserving the s.logger.ErrorContext call and its fields),
otherwise keep the existing Internal log+grpcstatus.Errorf behavior; reference
dao.ErrNotFound, s.logger.ErrorContext, templateID, grpcstatus.Errorf and
grpccodes.Internal/InvalidArgument and add an import for the dao package if not
already present.

---

Duplicate comments:
In `@internal/servers/private_compute_instances_server.go`:
- Around line 198-205: The current flow validates only when mask includes
spec.template or spec.template_parameters and then calls s.generic.Update, which
can persist an invalid effective spec; instead, fetch the current object (via
existing fetch method used elsewhere), merge the incoming masked spec into the
current object's spec before calling
fetchAndValidateTemplate/validateSpecWithDefaults to resolve the effective
template and apply defaults, ensure the merged/validated spec passes validation,
and only then call s.generic.Update with the original request (or with the
merged spec applied) so updates that only touch template_parameters or remove
template-required defaults are correctly validated; use hasMaskPrefix,
fetchAndValidateTemplate, validateSpecWithDefaults and s.generic.Update as the
reference points when implementing this change.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce896e17-0f4e-4fcc-98c4-f85dc72cc13f

📥 Commits

Reviewing files that changed from the base of the PR and between 36d3083 and 1185cb2.

⛔ Files ignored due to path filters (4)
  • internal/api/osac/private/v1/compute_instance_template_type.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/private/v1/compute_instance_template_type_protoopaque.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/public/v1/compute_instance_template_type.pb.go is excluded by !**/*.pb.go
  • internal/api/osac/public/v1/compute_instance_template_type_protoopaque.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (9)
  • internal/servers/compute_instances_server_test.go
  • internal/servers/private_compute_instances_server.go
  • internal/servers/private_compute_instances_server_test.go
  • internal/testing/database.go
  • internal/utils/spec_defaults.go
  • internal/utils/spec_defaults_test.go
  • it/it_compute_subnet_test.go
  • proto/private/osac/private/v1/compute_instance_template_type.proto
  • proto/public/osac/public/v1/compute_instance_template_type.proto
✅ Files skipped from review due to trivial changes (3)
  • internal/testing/database.go
  • proto/public/osac/public/v1/compute_instance_template_type.proto
  • internal/utils/spec_defaults_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/servers/compute_instances_server_test.go
  • proto/private/osac/private/v1/compute_instance_template_type.proto

Comment thread internal/utils/spec_defaults.go
@openshift-ci-robot

openshift-ci-robot commented Apr 16, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Adds validation of compute instances using fetched template spec default values.

The gist of this is we fetch the template (was already occurring), but the template we get back now includes spec defaults. We take the compute instance request body, populate fields on the request body from the spec defaults (such as cpu cores, memory etc.) and then attempt to validate the payload. The result is users can get additoinal feedback on fields they must define if the template doesn't define them.

For example, if we had a template that had NO defaults defined, the user can now see they need to define fields such as cores, memory etc. at creation time rather than having to debug why their VM won't spin up later on.

./fulfillment-cli create computeinstance --name test --template test-no-defaults
Error: failed to create compute instance: rpc error: code = InvalidArgument desc = the following required spec fields are missing: boot_disk, cores, image, memory_gib, run_strategy

Requires osac-project/osac-aap#246

Summary by CodeRabbit

  • New Features

  • Templates can include spec defaults (CPU, memory, image, boot disk, run strategy) applied when creating instances.

  • Improvements

  • Creation/update now applies template defaults during validation; user-provided fields take precedence and are preserved. Validation reports all missing required fields and rejects invalid run strategy values.

  • Tests

  • Added unit and integration tests for defaulting, validation, persistence semantics, and error messages.

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-robot

openshift-ci-robot commented Apr 16, 2026 •

Copy link
Copy Markdown

@DakCrowder: This pull request references MGMT-23769 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 bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Adds validation of compute instances using fetched template spec default values.

The gist of this is we fetch the template (was already occurring), but the template we get back now includes spec defaults. We take the compute instance request body, populate fields on the request body from the spec defaults (such as cpu cores, memory etc.) and then attempt to validate the payload. The result is users can get additoinal feedback on fields they must define if the template doesn't define them.

For example, if we had a template that had NO defaults defined, the user can now see they need to define fields such as cores, memory etc. at creation time rather than having to debug why their VM won't spin up later on.

./fulfillment-cli create computeinstance --name test --template test-no-defaults
Error: failed to create compute instance: rpc error: code = InvalidArgument desc = the following required spec fields are missing: boot_disk, cores, image, memory_gib, run_strategy

Requires osac-project/osac-aap#246

Note: Update logic has not been changed. I realized that there are some unclear boundaries around how we update fields with relation to templates and update masks and that requires some more consensus / thought.

Summary by CodeRabbit

  • New Features

  • Templates can include spec defaults (CPU, memory, image, boot disk, run strategy) applied when creating instances.

  • Improvements

  • Creation/update now applies template defaults during validation; user-provided fields take precedence and are preserved. Validation reports all missing required fields and rejects invalid run strategy values.

  • Tests

  • Added unit and integration tests for defaulting, validation, persistence semantics, and error messages.

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.

handle, err := sql.Open("pgx", url)
Expect(err).ToNot(HaveOccurred())
Eventually(handle.Ping, 10, 1).ShouldNot(HaveOccurred())
Eventually(handle.Ping, 30, 1).ShouldNot(HaveOccurred())

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.

My local environment (on my poor little thinkpad) was consistently timing out here running tests, bumped this up due to hitting it.

@akshaynadkarni

akshaynadkarni commented Apr 17, 2026 •

Copy link
Copy Markdown
Contributor

@DakCrowder
Nice work on the validation layer, the ApplySpecDefaults / ValidateRequiredSpecFields split is clean and well-tested. I had a question about the end-to-end flow though.

I see the tests at L650-675 assert that template defaults are intentionally not stored on the object ("the template is the source of truth at render time"). I understand the reasoning, but I'm wondering how this works with the current CRD and controller.

When the controller reconciles, addExplicitFields() only sets fields on the K8s CR where Has*() returns true. Since defaults aren't persisted, those checks return false, and the CR is created without cores, memoryGiB, etc. The CRD marks all five as required, so the K8s API server would reject it before the osac-operator/AAP can apply its own defaults from create_validate.yaml.

The ticket (MGMT-23769) has two expectations: (1) defaults populated automatically from the template, and (2) clear error when info is missing. This PR addresses (2) well. For (1), is the plan to also update the controller to merge template defaults in buildSpec(), or to relax the CRD to make those fields optional? Just want to make sure I'm not missing a companion change.

Comment thread internal/servers/private_compute_instances_server.go
Comment thread internal/utils/spec_defaults.go

// Create a compute instance without any spec fields — validation should pass
// because template defaults cover all required fields, but defaults should NOT
// be stored on the object (the template is the source of truth at render time):

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.

Curious about the design intent here. The test asserts defaults are NOT stored, with the comment "the template is the source of truth at render time." Could you help me understand how the controller handles this case? Looking at addExplicitFields(), it only populates fields where Has*() is true, so the K8s CR would be created without these spec fields. Since the CRD requires them, would the CR creation fail?

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.

Yes good observation / ty for raising. I had been waffling on the right approach here but I was missing a piece of the puzzle - which is the vendored mass open cloud aap arg spec has additional fields defined as template_parameters so I was seeing things populated in different ways that i was expecting.

After some more thought, I think there is a simpler option here - inspired by this comment on the associated aap pr I wonder if the defaults should just be template parameters with some well-known name or flag to indicate they are spec fields, we use the info defined (e.g. required, default value etc.) from the template parameter field definition to perform the validation, and then save them as a part of that block (continues behavior as-is of the template parameters are saved).

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.

I guess one difference / potential issue there is the template parameters only support a "flat" structure in comparison to nested spec fields like the image / boot_disk.

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.

To follow up on this - the code is now taking a snapshot of template default values at creation time (which is how we handle template_parameters) and store them - ensuring the fields are populated before the CR creation runs in the reconciler.

@DakCrowder
DakCrowder force-pushed the compute-instance-spec-defaults branch 3 times, most recently from a7566a3 to af48068 Compare April 23, 2026 18:58
@DakCrowder
DakCrowder force-pushed the compute-instance-spec-defaults branch 2 times, most recently from b7e6e15 to 53e2048 Compare April 24, 2026 16:44
@@ -189,7 +195,7 @@ func (s *PrivateComputeInstancesServer) Update(ctx context.Context,
}
}
if hasMaskPrefix(mask, "spec.template", "spec.template_parameters") {

@akshaynadkarni akshaynadkarni Apr 27, 2026 •

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.

Changing spec.template is allowed on update, but only fetchAndValidateTemplate runs here (template parameter validation). applySpecDefaults is not called, so the new template's spec defaults won't be applied for any fields the user hasn't explicitly set. The old template's defaults remain on the CI.

Two options:

  1. Call applySpecDefaults here too, so the new template's defaults take effect on update.
  2. Block template changes post-creation (make spec.template immutable after create), if switching templates on a running CI isn't intended to be supported.

Either way, the current behavior (silently keeping the old template's defaults after a template change) seems like it could surprise users.

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.

I was punting on update until I could get more clarity BUT after looking at clusters there is a method validateTemplateImmutability that (as named) ensures the corresponding fields on clusters cannot be changed on objects. Additionally, the compute_instace_type.proto indicates the template and template parameters should be immutable. Given this I think matching behavior can be introduced here aligned with option 2 above. If we want to change this behavior later then we can take it on more holistically alongside clusters / how we view templates as a whole.

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.

Updated to add the same behavior and ensures immutability as the proto def indicates

Comment thread internal/utils/spec_defaults.go Outdated
@DakCrowder
DakCrowder force-pushed the compute-instance-spec-defaults branch from 53e2048 to 314cb35 Compare April 28, 2026 15:06

@akshaynadkarni akshaynadkarni 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.

Code changes LGTM.

Prior to merging, can you update the PR description? It will be good to include any test results etc. so it's clear what the new behavior will be. Thanks.

@openshift-ci

openshift-ci Bot commented Apr 28, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: akshaynadkarni, DakCrowder

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

The pull request process is described 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

@DakCrowder

Copy link
Copy Markdown
Contributor Author

/unhold

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants