Skip to content

HYPERFLEET-657 - fix: enforce mandatory conditions in adapter status#60

Open
yasun1 wants to merge 1 commit intoopenshift-hyperfleet:mainfrom
yasun1:HYPERFLEET-657
Open

HYPERFLEET-657 - fix: enforce mandatory conditions in adapter status#60
yasun1 wants to merge 1 commit intoopenshift-hyperfleet:mainfrom
yasun1:HYPERFLEET-657

Conversation

@yasun1
Copy link
Contributor

@yasun1 yasun1 commented Feb 28, 2026

Reject adapter status updates missing mandatory conditions (Available, Applied, Health) or containing Unknown status. Returns HTTP 204 and preserves existing status to prevent loss of critical cluster state.

Changes:

  • Add condition type constants in pkg/api/status_types.go
  • Validate mandatory conditions in cluster/nodepool services
  • Replace hardcoded condition strings with constants
  • Add 4 new tests, update 8 existing tests for validation
  • Update integration tests to use constants

All tests passing: 416 unit, 51 integration, 0 lint issues

Summary by CodeRabbit

  • New Features

    • Added standardized condition type identifiers to the public API for resource and adapter status management.
  • Bug Fixes

    • Implemented stricter validation for adapter status updates to reject submissions with missing or invalid mandatory conditions, preventing incomplete or malformed status data from being stored.
  • Tests

    • Expanded test coverage for validation scenarios and mandatory condition handling.

Reject adapter status updates missing mandatory conditions (Available,
Applied, Health) or containing Unknown status. Returns HTTP 204 and
preserves existing status to prevent loss of critical cluster state.

Changes:
- Add condition type constants in pkg/api/status_types.go
- Validate mandatory conditions in cluster/nodepool services
- Replace hardcoded condition strings with constants
- Add 4 new tests, update 8 existing tests for validation
- Update integration tests to use constants

All tests passing: 416 unit, 51 integration, 0 lint issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@openshift-ci openshift-ci bot requested review from AlexVulaj and tirthct February 28, 2026 08:31
@openshift-ci
Copy link

openshift-ci bot commented Feb 28, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign jsell-rh 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

@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

Walkthrough

This pull request introduces four new public condition type constants to the API (ConditionTypeAvailable, ConditionTypeApplied, ConditionTypeHealth, ConditionTypeReady) and implements strict validation of mandatory adapter conditions across cluster and node pool services. When processing adapter status updates, the services now validate that all mandatory conditions (Available, Applied, Health) are present and not in Unknown status; updates failing validation are rejected without persisting status. Valid updates trigger status aggregation. All internal constant references are replaced with the public API constants, and tests are updated to verify rejection behavior and mandatory condition preservation.

Sequence Diagram

sequenceDiagram
    participant Adapter
    participant Service as Cluster/NodePool Service
    participant Storage as Status Storage
    participant Aggregation as Status Aggregation

    Adapter->>Service: POST adapter status<br/>(conditions with Available, Applied, Health)
    
    rect rgba(200, 100, 100, 0.5)
        Service->>Service: Build condition map
        Service->>Service: Validate mandatory conditions<br/>(Available, Applied, Health)
        alt Invalid (missing or Unknown)
            Service->>Service: Log rejection reason
            Service-->>Adapter: 204 No Content
            Note over Service: Update discarded
        end
    end
    
    rect rgba(100, 200, 100, 0.5)
        alt Valid (all present, not Unknown)
            Service->>Storage: Upsert adapter status<br/>(complete replacement)
            Service->>Aggregation: Trigger status aggregation
            Aggregation->>Aggregation: Compute Available/Ready<br/>conditions
            Aggregation-->>Service: Aggregation complete
            Service-->>Adapter: 200/201 Success
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • PR #39 — Introduced the condition-based status model (Available/Ready) and API/types changes including ConditionType constants that this PR now extends and validates across service layers
  • PR #40 — Modifies the same service codepaths (cluster.go, node_pool.go, status_aggregation.go) to change how adapter condition types are determined and used, directly overlapping with mandatory condition validation logic
  • PR #4 — Refactors adapter-condition semantics and status aggregation machinery that this PR builds upon with stricter mandatory-condition validation and public constant usage

Suggested labels

lgtm, approved

Suggested reviewers

  • jsell-rh
  • mbrudnoy
  • aredenba-rh
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'HYPERFLEET-657 - fix: enforce mandatory conditions in adapter status' directly describes the main change: implementing validation to enforce mandatory condition types in adapter status updates.
Docstring Coverage ✅ Passed Docstring coverage is 81.08% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
pkg/services/cluster_test.go (2)

943-946: Inconsistent use of string literals for condition types.

Lines 944, 1024, 1071, 1130, and 1156 use the string literal "Available" instead of api.ConditionTypeAvailable. For consistency with the rest of the file, consider using the API constants throughout.

♻️ Suggested fix for line 944 (apply similar fixes to other occurrences)
 	validConditions := []api.AdapterCondition{
-		{Type: "Available", Status: api.AdapterConditionTrue, LastTransitionTime: time.Now()},
+		{Type: api.ConditionTypeAvailable, Status: api.AdapterConditionTrue, LastTransitionTime: time.Now()},
 		{Type: api.ConditionTypeApplied, Status: api.AdapterConditionTrue, LastTransitionTime: time.Now()},
 		{Type: api.ConditionTypeHealth, Status: api.AdapterConditionTrue, LastTransitionTime: time.Now()},
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/services/cluster_test.go` around lines 943 - 946, Replace the hard-coded
string "Available" used for AdapterCondition Type with the API constant to
maintain consistency: update the entries in validConditions (and the other
occurrences at the noted locations) to use api.ConditionTypeAvailable instead of
the string literal; ensure the type field remains of the same type
(api.AdapterCondition.Type) and run tests to verify no type mismatches.

857-864: Inconsistent use of string literal instead of API constant.

Line 858 uses the string literal "Ready" while the rest of the file uses api.ConditionTypeReady. For consistency, consider using the API constant.

♻️ Suggested fix
 		{
-			Type:               "Ready",
+			Type:               api.ConditionTypeReady,
 			Status:             api.ConditionFalse,
 			ObservedGeneration: 1,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/services/cluster_test.go` around lines 857 - 864, Replace the hard-coded
string "Ready" in the Condition struct literal with the API constant to maintain
consistency: change the Type field value from the string literal to use
api.ConditionTypeReady (the same constant used elsewhere in this file/tests),
ensuring imports/reference to api remain correct.
pkg/services/node_pool.go (1)

269-292: Validation logic is correct; consider structured logging improvement.

The mandatory condition validation correctly mirrors the cluster.go implementation. However, similar to the cluster service, consider using structured logging fields instead of fmt.Sprintf.

♻️ Suggested refactor for structured logging
 	for _, mandatoryType := range mandatoryConditionTypes {
 		status, exists := conditionMap[mandatoryType]
 		if !exists {
 			// Missing mandatory condition - discard the update
-			logger.With(ctx, logger.FieldNodePoolID, nodePoolID).
-				Info(fmt.Sprintf("Discarding adapter status update from %s: missing mandatory condition %s",
-					adapterStatus.Adapter, mandatoryType))
+			logger.With(ctx, logger.FieldNodePoolID, nodePoolID, "adapter", adapterStatus.Adapter, "missing_condition", mandatoryType).
+				Info("Discarding adapter status update: missing mandatory condition")
 			return nil, nil
 		}
 		if status == api.AdapterConditionUnknown {
 			// Mandatory condition has Unknown status - discard the update
-			logger.With(ctx, logger.FieldNodePoolID, nodePoolID).
-				Info(fmt.Sprintf("Discarding adapter status update from %s: mandatory condition %s has Unknown status",
-					adapterStatus.Adapter, mandatoryType))
+			logger.With(ctx, logger.FieldNodePoolID, nodePoolID, "adapter", adapterStatus.Adapter, "condition", mandatoryType).
+				Info("Discarding adapter status update: mandatory condition has Unknown status")
 			return nil, nil
 		}
 	}

Based on learnings: "In the openshift-hyperfleet/hyperfleet-api repository, NewOCMLogger(ctx) is deprecated. Switch to the slog-based logger and use logger.With(ctx, ...) to produce structured, context-aware logs."

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

In `@pkg/services/node_pool.go` around lines 269 - 292, The logging uses
fmt.Sprintf for messages in the mandatory condition checks; replace these with
structured, context-aware logs using logger.With(ctx, logger.FieldNodePoolID,
nodePoolID, "adapter", adapterStatus.Adapter, "mandatoryCondition",
mandatoryType, "status", status) and then call Info with a short message (e.g.,
"Discarding adapter status update") so fields carry the details; update both the
missing-condition and Unknown-status branches and keep the validation logic
around conditionMap, mandatoryConditionTypes, and adapterStatus.Adapter
unchanged.
pkg/services/cluster.go (1)

272-295: Consider using structured logging fields instead of fmt.Sprintf.

The current approach uses fmt.Sprintf to format the log message. Per repository conventions, structured logging with fields is preferred for better log parsing and filtering.

♻️ Suggested refactor for structured logging
 	for _, mandatoryType := range mandatoryConditionTypes {
 		status, exists := conditionMap[mandatoryType]
 		if !exists {
 			// Missing mandatory condition - discard the update
 			ctx = logger.WithClusterID(ctx, clusterID)
-			logger.Info(ctx, fmt.Sprintf("Discarding adapter status update from %s: missing mandatory condition %s",
-				adapterStatus.Adapter, mandatoryType))
+			logger.With(ctx, "adapter", adapterStatus.Adapter, "missing_condition", mandatoryType).
+				Info("Discarding adapter status update: missing mandatory condition")
 			return nil, nil
 		}
 		if status == api.AdapterConditionUnknown {
 			// Mandatory condition has Unknown status - discard the update
 			ctx = logger.WithClusterID(ctx, clusterID)
-			logger.Info(ctx, fmt.Sprintf("Discarding adapter status update from %s: mandatory condition %s has Unknown status",
-				adapterStatus.Adapter, mandatoryType))
+			logger.With(ctx, "adapter", adapterStatus.Adapter, "condition", mandatoryType).
+				Info("Discarding adapter status update: mandatory condition has Unknown status")
 			return nil, nil
 		}
 	}

Based on learnings: "In the openshift-hyperfleet/hyperfleet-api repository, NewOCMLogger(ctx) is deprecated. Switch to the slog-based logger and use logger.With(ctx, ...) to produce structured, context-aware logs."

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

In `@pkg/services/cluster.go` around lines 272 - 295, Replace the
fmt.Sprintf-based logs with structured slog-style logging using logger.With(...)
and pass clusterID, adapter and mandatory condition as fields; for the
missing-condition case call something like ctx = logger.With(ctx, "cluster_id",
clusterID, "adapter", adapterStatus.Adapter, "mandatory_condition",
mandatoryType) and then logger.Info(ctx, "Discarding adapter status update:
missing mandatory condition"); do the same for the Unknown-status branch (use
the same fields and a message like "Discarding adapter status update: mandatory
condition has Unknown status"), removing fmt.Sprintf and keeping the existing
early returns; references: conditionMap, mandatoryConditionTypes,
logger.WithClusterID / logger.With, logger.Info, adapterStatus.Adapter,
mandatoryType.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/services/cluster_test.go`:
- Around line 943-946: Replace the hard-coded string "Available" used for
AdapterCondition Type with the API constant to maintain consistency: update the
entries in validConditions (and the other occurrences at the noted locations) to
use api.ConditionTypeAvailable instead of the string literal; ensure the type
field remains of the same type (api.AdapterCondition.Type) and run tests to
verify no type mismatches.
- Around line 857-864: Replace the hard-coded string "Ready" in the Condition
struct literal with the API constant to maintain consistency: change the Type
field value from the string literal to use api.ConditionTypeReady (the same
constant used elsewhere in this file/tests), ensuring imports/reference to api
remain correct.

In `@pkg/services/cluster.go`:
- Around line 272-295: Replace the fmt.Sprintf-based logs with structured
slog-style logging using logger.With(...) and pass clusterID, adapter and
mandatory condition as fields; for the missing-condition case call something
like ctx = logger.With(ctx, "cluster_id", clusterID, "adapter",
adapterStatus.Adapter, "mandatory_condition", mandatoryType) and then
logger.Info(ctx, "Discarding adapter status update: missing mandatory
condition"); do the same for the Unknown-status branch (use the same fields and
a message like "Discarding adapter status update: mandatory condition has
Unknown status"), removing fmt.Sprintf and keeping the existing early returns;
references: conditionMap, mandatoryConditionTypes, logger.WithClusterID /
logger.With, logger.Info, adapterStatus.Adapter, mandatoryType.

In `@pkg/services/node_pool.go`:
- Around line 269-292: The logging uses fmt.Sprintf for messages in the
mandatory condition checks; replace these with structured, context-aware logs
using logger.With(ctx, logger.FieldNodePoolID, nodePoolID, "adapter",
adapterStatus.Adapter, "mandatoryCondition", mandatoryType, "status", status)
and then call Info with a short message (e.g., "Discarding adapter status
update") so fields carry the details; update both the missing-condition and
Unknown-status branches and keep the validation logic around conditionMap,
mandatoryConditionTypes, and adapterStatus.Adapter unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab950d5 and e277266.

📒 Files selected for processing (7)
  • pkg/api/status_types.go
  • pkg/services/cluster.go
  • pkg/services/cluster_test.go
  • pkg/services/node_pool.go
  • pkg/services/node_pool_test.go
  • pkg/services/status_aggregation.go
  • test/integration/adapter_status_test.go

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.

1 participant