-
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
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
463ca4b
a5adda6
7bb6b2d
929ad77
2e624a6
f22eab0
cbda303
755abc5
55d5c43
b91bd45
29c7d6b
92ca512
05684ad
54fc351
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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.
Show resolved
Hide 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
Show resolved
Hide resolved
|
||
| # ============================================================================ | ||
| # 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
Show resolved
Hide resolved
|
||
| 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.
Show resolved
Hide 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
Collaborator
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" | ||
Uh oh!
There was an error while loading. Please reload this page.