This repository was archived by the owner on Apr 16, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Hyperfleet-267 - feat: Implement Minimal Real GCP Validation and Related Helm Chart #10
Merged
xueli181114
merged 14 commits into
openshift-hyperfleet:main
from
86254860:HYPERFLEET-267
Jan 26, 2026
Merged
Changes from 4 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
463ca4b
HYPERFLEET-267 - feat: Implement real GCP validator
86254860 a5adda6
Add Dockerfile and Makefile
86254860 7bb6b2d
Add README.md
86254860 929ad77
Add GCP validation adapter configurations and support real validator …
86254860 2e624a6
Add docstring and update based on coderabbit review comments
86254860 f22eab0
Update with coderabbit review comments
86254860 cbda303
Introduce useDummy to indicate real or dummy validation, and refine a…
86254860 755abc5
Replace os.Setenv with GinkgoT().Setenv and use MAX_WAIT_TIME_SECONDS…
86254860 55d5c43
Support lazy initialization for gcp client, add integration tests and…
86254860 b91bd45
Add more test cases for dependency logic and support helm variable fo…
86254860 29c7d6b
Adjust format - replace tab with four spaces
86254860 92ca512
Support thread-safe and fix some issue with coderabbit review comments
86254860 05684ad
Remove confused Enabled of validator and update related test cases
86254860 54fc351
Remove StatusSkipped
86254860 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,317 @@ | ||
| # HyperFleet GCP Validation Adapter Configuration | ||
| # | ||
| # This adapter creates a validation job for GCP clusters to verify | ||
| # cluster readiness and configuration. | ||
| apiVersion: hyperfleet.redhat.com/v1alpha1 | ||
| kind: AdapterConfig | ||
| metadata: | ||
| name: validation-adapter | ||
| namespace: hyperfleet-system | ||
| labels: | ||
| hyperfleet.io/adapter-type: validation | ||
| hyperfleet.io/component: adapter | ||
| hyperfleet.io/provider: gcp | ||
| spec: | ||
| adapter: | ||
| version: "0.1.0" | ||
| # ============================================================================ | ||
| # HyperFleet API Configuration | ||
| # ============================================================================ | ||
| hyperfleetApi: | ||
| timeout: 2s | ||
| retryAttempts: 3 | ||
| # ============================================================================ | ||
| # Kubernetes Configuration | ||
| # ============================================================================ | ||
| kubernetes: | ||
| apiVersion: "batch/v1" | ||
| # ============================================================================ | ||
| # Parameters | ||
| # ============================================================================ | ||
| params: | ||
| - name: "hyperfleetApiBaseUrl" | ||
| source: "env.HYPERFLEET_API_BASE_URL" | ||
| type: "string" | ||
| description: "Base URL for the HyperFleet API" | ||
| required: true | ||
| - name: "hyperfleetApiVersion" | ||
| source: "env.HYPERFLEET_API_VERSION" | ||
| type: "string" | ||
| default: "v1" | ||
| description: "API version to use" | ||
| - name: "clusterId" | ||
| source: "event.id" | ||
| type: "string" | ||
| description: "Unique identifier for the target cluster" | ||
| required: true | ||
| - name: "statusReporterImage" | ||
| source: "env.STATUS_REPORTER_IMAGE" | ||
| type: "string" | ||
| default: "quay.io/rh-ee-dawang/status-reporter:dev-04e8d0a" | ||
| description: "Container image for the status reporter" | ||
| # GCP Validator configuration | ||
| - name: "gcpValidatorImage" | ||
| source: "env.GCP_VALIDATOR_IMAGE" | ||
| type: "string" | ||
| default: "quay.io/rh-ee-dawang/gcp-validator:latest" | ||
| description: "GCP validator container image" | ||
| - name: "disabledValidators" | ||
| source: "env.DISABLED_VALIDATORS" | ||
| type: "string" | ||
| default: "" | ||
| description: "Comma-separated list of validators to disable" | ||
| - name: "requiredApis" | ||
| source: "env.REQUIRED_APIS" | ||
| type: "string" | ||
| default: "compute.googleapis.com,iam.googleapis.com,cloudresourcemanager.googleapis.com" | ||
| description: "Comma-separated list of required GCP APIs to validate" | ||
| - name: "resultPath" | ||
| source: "env.RESULTS_PATH" | ||
| type: "string" | ||
| default: "/results/adapter-result.json" | ||
| description: "Adapter shared result path with status reporter" | ||
| - name: "maxWaitTimeSeconds" | ||
| source: "env.MAX_WAIT_TIME_SECONDS" | ||
| type: "string" | ||
| default: "300" | ||
| description: "Maximum time to wait for validation completion" | ||
| - name: "gcpValidatorServiceAccount" | ||
| source: "env.GCP_VALIDATOR_SERVICE_ACCOUNT" | ||
| type: "string" | ||
| default: "gcp-validator-job-sa" | ||
| description: "Kubernetes ServiceAccount name for the validator job" | ||
| - name: "managedByResourceName" | ||
| source: "env.MANAGED_By_RESOURCE_NAME" | ||
| type: "string" | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| default: "validation-adapter" | ||
| description: "The value for hyperfleet.io/managed-by" | ||
| - name: "createdByResourceName" | ||
| source: "env.CREATED_BY_RESOURCE_NAME" | ||
| type: "string" | ||
| default: "hyperfleet-adapter" | ||
| description: "The value for hyperfleet.io/created-by:" | ||
|
86254860 marked this conversation as resolved.
Outdated
|
||
| # ============================================================================ | ||
| # Preconditions | ||
| # ============================================================================ | ||
| # Preconditions run before resource operations to validate state | ||
| preconditions: | ||
| - name: "clusterStatus" | ||
| apiCall: | ||
| method: "GET" | ||
| url: "{{ .hyperfleetApiBaseUrl }}/api/hyperfleet/{{ .hyperfleetApiVersion }}/clusters/{{ .clusterId }}" | ||
| timeout: 10s | ||
| retryAttempts: 3 | ||
| retryBackoff: "exponential" | ||
| capture: | ||
| - name: "clusterName" | ||
| field: "name" | ||
| - name: "clusterPhase" | ||
| field: "status.phase" | ||
| - name: "generationId" | ||
| field: "generation" | ||
| # Customer GCP project ID | ||
| - name: "projectId" | ||
| field: "spec.platform.gcp.projectID" | ||
| conditions: | ||
| - field: "clusterPhase" | ||
| operator: "in" | ||
| values: ["NotReady", "Ready"] | ||
| # Ensure Customer GCP project ID is configured | ||
| - field: "projectId" | ||
| operator: "exists" | ||
|
|
||
| - name: "clusterAdapterStatus" | ||
| apiCall: | ||
| method: "GET" | ||
| url: "{{ .hyperfleetApiBaseUrl }}/api/hyperfleet/{{ .hyperfleetApiVersion }}/clusters/{{ .clusterId }}/statuses" | ||
| timeout: 10s | ||
| retryAttempts: 3 | ||
| retryBackoff: "exponential" | ||
| capture: | ||
| - name: "clusterNamespaceStatus" | ||
| field: "{.items[?(@.adapter=='landing-zone-adapter')].data.namespace.status}" | ||
| conditions: | ||
| - field: "clusterNamespaceStatus" | ||
| operator: "equals" | ||
| values: "Active" | ||
| # ============================================================================ | ||
| # Resources | ||
| # ============================================================================ | ||
| resources: | ||
| # ========================================================================== | ||
| # Resource: ServiceAccount for GCP Validation Job | ||
| # ========================================================================== | ||
| - name: "gcpValidationServiceAccount" | ||
| manifest: | ||
| # ServiceAccount for the validator job | ||
| apiVersion: v1 | ||
| kind: ServiceAccount | ||
| metadata: | ||
| name: "{{ .gcpValidatorServiceAccount }}" | ||
| namespace: "{{ .clusterId | lower }}" | ||
| labels: | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| hyperfleet.io/resource-type: "service-account" | ||
| annotations: | ||
| hyperfleet.io/created-by: "{{ .createdByResourceName }}" | ||
| hyperfleet.io/generation: "{{ .generationId }}" | ||
| discovery: | ||
| bySelectors: | ||
| labelSelector: | ||
| hyperfleet.io/resource-type: "service-account" | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| # ========================================================================== | ||
| # Resource: Role with necessary permissions for status reporter | ||
| # ========================================================================== | ||
| - name: "gcpValidationRole" | ||
|
86254860 marked this conversation as resolved.
Outdated
|
||
| manifest: | ||
| # Role with necessary permissions for status reporter | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: Role | ||
| metadata: | ||
| name: status-reporter | ||
| namespace: "{{ .clusterId | lower }}" | ||
| labels: | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| hyperfleet.io/resource-type: "role" | ||
| annotations: | ||
| hyperfleet.io/created-by: "{{ .createdByResourceName }}" | ||
| hyperfleet.io/generation: "{{ .generationId }}" | ||
| rules: | ||
| # Permission to get and update job status | ||
| - apiGroups: [ "batch" ] | ||
| resources: [ "jobs" ] | ||
| verbs: [ "get" ] | ||
| - apiGroups: [ "batch" ] | ||
| resources: [ "jobs/status" ] | ||
| verbs: [ "get", "update", "patch" ] | ||
| # Permission to get pod status | ||
| - apiGroups: [ "" ] | ||
| resources: [ "pods" ] | ||
| verbs: [ "get", "list" ] | ||
| discovery: | ||
| bySelectors: | ||
| labelSelector: | ||
| hyperfleet.io/resource-type: "role" | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| # ========================================================================== | ||
| # Rolebinding to grant permissions to the service account | ||
| # ========================================================================== | ||
| - name: "gcpValidationRoleBinding" | ||
| manifest: | ||
| # RoleBinding to grant permissions to the service account | ||
| apiVersion: rbac.authorization.k8s.io/v1 | ||
| kind: RoleBinding | ||
| metadata: | ||
| name: status-reporter | ||
| namespace: "{{ .clusterId | lower }}" | ||
| labels: | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| hyperfleet.io/resource-type: "role-binding" | ||
| annotations: | ||
| hyperfleet.io/created-by: "{{ .createdByResourceName }}" | ||
| hyperfleet.io/generation: "{{ .generationId }}" | ||
| roleRef: | ||
| apiGroup: rbac.authorization.k8s.io | ||
| kind: Role | ||
| name: status-reporter | ||
| subjects: | ||
| - kind: ServiceAccount | ||
| name: "{{ .gcpValidatorServiceAccount }}" | ||
| namespace: "{{ .clusterId | lower }}" | ||
| discovery: | ||
| bySelectors: | ||
| labelSelector: | ||
| hyperfleet.io/resource-type: "role-binding" | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| # ========================================================================== | ||
| # Resource: GCP Validation Job | ||
| # ========================================================================== | ||
| - name: "gcpValidationJob" | ||
| manifest: | ||
| ref: "./validation-job-adapter-task.yaml" | ||
| discovery: | ||
| bySelectors: | ||
| labelSelector: | ||
| hyperfleet.io/resource-type: "validation-job" | ||
| hyperfleet.io/cluster-id: "{{ .clusterId }}" | ||
| hyperfleet.io/managed-by: "{{ .managedByResourceName }}" | ||
| # ============================================================================ | ||
| # Post-Processing | ||
| # ============================================================================ | ||
| post: | ||
| payloads: | ||
| # Build status payload inline | ||
| - name: "clusterStatusPayload" | ||
| build: | ||
| adapter: "{{ .metadata.name }}" | ||
| conditions: | ||
| # Applied: Job successfully created | ||
| - type: "Applied" | ||
| status: | ||
| expression: | | ||
| has(resources.gcpValidationJob) ? "True" : "False" | ||
| reason: | ||
| expression: | | ||
| has(resources.gcpValidationJob) | ||
| ? "JobApplied" | ||
| : "JobPending" | ||
| message: | ||
| expression: | | ||
| has(resources.gcpValidationJob) | ||
| ? "Validation job applied successfully" | ||
| : "Validation job is pending to applied" | ||
|
86254860 marked this conversation as resolved.
|
||
| # Available: Check job status conditions | ||
| - type: "Available" | ||
| status: | ||
| expression: | | ||
| resources.?gcpValidationJob.?status.?conditions.orValue([]).exists(c, c.type == "Available") | ||
| ? resources.gcpValidationJob.status.conditions.filter(c, c.type == "Available")[0].status : "False" | ||
|
Comment on lines
+273
to
+277
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we have a third value
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to openshift-hyperfleet/architecture#79, it requires several changes from different CLM components. I'll update this logic in another PR. |
||
| reason: | ||
| expression: | | ||
| resources.?gcpValidationJob.?status.?conditions.orValue([]).exists(c, c.type == "Available") | ||
| ? resources.gcpValidationJob.status.conditions.filter(c, c.type == "Available")[0].reason | ||
| : resources.?gcpValidationJob.?status.?conditions.orValue([]).exists(c, c.type == "Failed") ? "ValidationFailed" | ||
| : resources.?gcpValidationJob.?status.hasValue() ? "ValidationInProgress" : "ValidationPending" | ||
| message: | ||
| expression: | | ||
| resources.?gcpValidationJob.?status.?conditions.orValue([]).exists(c, c.type == "Available") | ||
| ? resources.gcpValidationJob.status.conditions.filter(c, c.type == "Available")[0].message | ||
| : resources.?gcpValidationJob.?status.?conditions.orValue([]).exists(c, c.type == "Failed") ? "Validation failed" | ||
| : resources.?gcpValidationJob.?status.hasValue() ? "Validation in progress" : "Validation is pending" | ||
| # Health: Adapter execution status (runtime) | ||
| - type: "Health" | ||
| status: | ||
| expression: | | ||
| adapter.?executionStatus.orValue("") == "success" ? "True" : (adapter.?executionStatus.orValue("") == "failed" ? "False" : "Unknown") | ||
| reason: | ||
| expression: | | ||
| adapter.?errorReason.orValue("") != "" ? adapter.?errorReason.orValue("") : "Healthy" | ||
| message: | ||
| expression: | | ||
| adapter.?errorMessage.orValue("") != "" ? adapter.?errorMessage.orValue("") : "All adapter operations completed successfully" | ||
| # Event generation ID metadata field needs to use expression to avoid interpolation issues | ||
| observed_generation: | ||
| expression: "generationId" | ||
| observed_time: "{{ now | date \"2006-01-02T15:04:05Z07:00\" }}" | ||
| # ============================================================================ | ||
| # Post Actions | ||
| # ============================================================================ | ||
| postActions: | ||
| - name: "reportClusterStatus" | ||
| apiCall: | ||
| method: "POST" | ||
| url: "{{ .hyperfleetApiBaseUrl }}/api/hyperfleet/{{ .hyperfleetApiVersion }}/clusters/{{ .clusterId }}/statuses" | ||
| body: "{{ .clusterStatusPayload }}" | ||
| timeout: 30s | ||
| retryAttempts: 3 | ||
| retryBackoff: "exponential" | ||
| headers: | ||
| - name: "Content-Type" | ||
| value: "application/json" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.