From af0299f1e4781b19a34c0d1f4c855ab59ec0dc98 Mon Sep 17 00:00:00 2001 From: mliptak0 Date: Wed, 24 Jun 2026 12:49:17 +0200 Subject: [PATCH] HYPERFLEET-1108 - feat: Add e2e.hyperfleet.io/run-id label for e2e-gcp environment, label resources created by adapters --- Makefile | 13 +- .../cl-deployment/adapter-task-config.yaml | 4 + .../adapter-task-resource-deployment.yaml | 2 + .../adapters/cl-job/adapter-task-config.yaml | 4 + .../cl-job/adapter-task-resource-job.yaml | 26 ++- .../cl-maestro/adapter-task-config.yaml | 5 + .../adapter-task-resource-manifestwork.yaml | 203 +++++++++--------- .../cl-namespace/adapter-task-config.yaml | 7 +- helmfile/helmfile.yaml.gotmpl | 3 + helmfile/values/base-adapter.yaml.gotmpl | 10 + helmfile/values/base-api.yaml.gotmpl | 7 +- helmfile/values/base-sentinel.yaml.gotmpl | 5 + 12 files changed, 172 insertions(+), 117 deletions(-) diff --git a/Makefile b/Makefile index 763207b..303d1ff 100644 --- a/Makefile +++ b/Makefile @@ -292,7 +292,7 @@ check-jq: ## Verify jq is installed @echo "OK: jq found" .PHONY: check-helmfile-env -check-helmfile-env: check-helmfile check-kubectl-context check-helmfile-env-generated ## Verify kubectl context and generated values directory exists +check-helmfile-env: check-helmfile check-kubectl-context check-helmfile-env-generated check-e2e-run-id ## Verify kubectl context and generated values directory exists .PHONY: check-helmfile-env-generated check-helmfile-env-generated: ## Check that the generated directory exists based on HELMFILE_ENV @@ -315,6 +315,17 @@ check-kubectl-context: check-kubectl ## Verify kubectl context matches HELMFILE_ echo "OK: kubectl context matches HELMFILE_ENV=$(HELMFILE_ENV)"; \ fi; +.PHONY: check-e2e-run-id +check-e2e-run-id: ## Verify E2E_RUN_ID is set for e2e-gcp environment + @if [ "$(HELMFILE_ENV)" = "e2e-gcp" ]; then \ + if [ -z "$(E2E_RUN_ID)" ]; then \ + echo "ERROR: E2E_RUN_ID must be set when HELMFILE_ENV=e2e-gcp"; \ + echo " Usage: E2E_RUN_ID= make install-hyperfleet"; \ + exit 1; \ + fi; \ + echo "OK: E2E_RUN_ID=$(E2E_RUN_ID)"; \ + fi; + .PHONY: check-terraform check-terraform: ## Verify terraform is installed @command -v terraform >/dev/null 2>&1 || { echo "ERROR: terraform is not installed"; exit 1; } diff --git a/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-config.yaml b/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-config.yaml index 406ae4e..3ae40d3 100644 --- a/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-config.yaml +++ b/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-config.yaml @@ -6,6 +6,10 @@ params: source: "event.id" type: "string" required: true + - name: "e2eRunId" + source: "env.E2E_RUN_ID" + type: "string" + required: false # Preconditions with valid operators and CEL expressions preconditions: diff --git a/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-resource-deployment.yaml b/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-resource-deployment.yaml index 6f66b37..86203f9 100644 --- a/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-resource-deployment.yaml +++ b/helmfile/configs/e2e/adapters/cl-deployment/adapter-task-resource-deployment.yaml @@ -7,6 +7,7 @@ metadata: labels: hyperfleet.io/cluster-id: "{{ .clusterId }}" hyperfleet.io/resource-type: "deployment" + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" annotations: hyperfleet.io/generation: "{{ .generationSpec }}" spec: @@ -20,6 +21,7 @@ spec: labels: app: test hyperfleet.io/cluster-id: "{{ .clusterId }}" + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" spec: containers: - name: test diff --git a/helmfile/configs/e2e/adapters/cl-job/adapter-task-config.yaml b/helmfile/configs/e2e/adapters/cl-job/adapter-task-config.yaml index a59aac1..6b6ffad 100644 --- a/helmfile/configs/e2e/adapters/cl-job/adapter-task-config.yaml +++ b/helmfile/configs/e2e/adapters/cl-job/adapter-task-config.yaml @@ -6,6 +6,10 @@ params: source: "event.id" type: "string" required: true + - name: "e2eRunId" + source: "env.E2E_RUN_ID" + type: "string" + required: false # Preconditions with valid operators and CEL expressions preconditions: diff --git a/helmfile/configs/e2e/adapters/cl-job/adapter-task-resource-job.yaml b/helmfile/configs/e2e/adapters/cl-job/adapter-task-resource-job.yaml index bf61887..e640c35 100644 --- a/helmfile/configs/e2e/adapters/cl-job/adapter-task-resource-job.yaml +++ b/helmfile/configs/e2e/adapters/cl-job/adapter-task-resource-job.yaml @@ -8,22 +8,26 @@ metadata: hyperfleet.io/cluster-id: "{{ .clusterId }}" hyperfleet.io/resource-type: "job" app: test-job + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" annotations: hyperfleet.io/generation: "{{ .generationSpec }}" spec: backoffLimit: 0 template: + metadata: + labels: + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" spec: restartPolicy: Never containers: - - name: hello-world - image: alpine:3.19 - imagePullPolicy: IfNotPresent - command: ["/bin/sh", "-c", "echo 'Hello, World!'"] - resources: - requests: - memory: "32Mi" - cpu: "50m" - limits: - memory: "64Mi" - cpu: "100m" + - name: hello-world + image: alpine:3.19 + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "-c", "echo 'Hello, World!'"] + resources: + requests: + memory: "32Mi" + cpu: "50m" + limits: + memory: "64Mi" + cpu: "100m" diff --git a/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-config.yaml b/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-config.yaml index 8978adf..e664c06 100644 --- a/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-config.yaml +++ b/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-config.yaml @@ -17,6 +17,11 @@ params: source: "env.NAMESPACE" type: "string" + - name: "e2eRunId" + source: "env.E2E_RUN_ID" + type: "string" + required: false + # Preconditions with valid operators and CEL expressions preconditions: - name: "clusterStatus" diff --git a/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-resource-manifestwork.yaml b/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-resource-manifestwork.yaml index 87dd7a8..d3ebd41 100644 --- a/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-resource-manifestwork.yaml +++ b/helmfile/configs/e2e/adapters/cl-maestro/adapter-task-resource-manifestwork.yaml @@ -13,6 +13,7 @@ metadata: hyperfleet.io/component: "infrastructure" hyperfleet.io/generation: "{{ .generation }}" hyperfleet.io/resource-group: "cluster-setup" + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" # Maestro-specific labels maestro.io/source-id: "{{ .adapter.name }}" @@ -27,26 +28,26 @@ metadata: app.kubernetes.io/part-of: "hyperfleet" app.kubernetes.io/managed-by: "cl-maestro" app.kubernetes.io/created-by: "{{ .adapter.name }}" -{{ if .platformType }} - hyperfleet.io/platform-type: "{{ .platformType }}" -{{ end }} + {{ if .platformType }} +hyperfleet.io/platform-type: "{{ .platformType }}" + {{ end }} - # Annotations for metadata and operational information - annotations: - # Tracking and lifecycle - hyperfleet.io/created-by: "cl-maestro-framework" - hyperfleet.io/managed-by: "{{ .adapter.name }}" - hyperfleet.io/generation: "{{ .generation }}" - hyperfleet.io/cluster-id: "{{ .clusterId }}" - hyperfleet.io/cluster-name: "{{ .clusterName }}" - hyperfleet.io/deployment-time: "{{ .timestamp }}" +# Annotations for metadata and operational information +annotations: + # Tracking and lifecycle + hyperfleet.io/created-by: "cl-maestro-framework" + hyperfleet.io/managed-by: "{{ .adapter.name }}" + hyperfleet.io/generation: "{{ .generation }}" + hyperfleet.io/cluster-id: "{{ .clusterId }}" + hyperfleet.io/cluster-name: "{{ .clusterName }}" + hyperfleet.io/deployment-time: "{{ .timestamp }}" - # Maestro-specific annotations - maestro.io/applied-time: "{{ .timestamp }}" - maestro.io/source-adapter: "{{ .adapter.name }}" + # Maestro-specific annotations + maestro.io/applied-time: "{{ .timestamp }}" + maestro.io/source-adapter: "{{ .adapter.name }}" - # Documentation - description: "Complete cluster setup including namespace, configuration, and RBAC" + # Documentation + description: "Complete cluster setup including namespace, configuration, and RBAC" # ManifestWork specification spec: @@ -56,89 +57,91 @@ spec: workload: # Kubernetes manifests array - injected by framework from business logic config manifests: - - apiVersion: v1 - kind: Namespace - metadata: - name: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" - labels: - app.kubernetes.io/component: adapter-task-config - app.kubernetes.io/instance: "{{ .adapter.name }}" - app.kubernetes.io/name: cl-maestro - app.kubernetes.io/transport: maestro - annotations: - hyperfleet.io/generation: "{{ .generation }}" - - apiVersion: v1 - kind: ConfigMap - data: - cluster_id: "{{ .clusterId }}" - cluster_name: "{{ .clusterName }}" -{{ if eq .platformType "gcp" }} - platform_tier: "cloud" -{{ else }} - platform_tier: "onprem" -{{ end }} -{{ range $i, $subnet := .subnets }} - subnet_{{ $subnet.id }}_name: "{{ $subnet.name }}" - subnet_{{ $subnet.id }}_cidr: "{{ $subnet.cidr }}" - subnet_{{ $subnet.id }}_role: "{{ $subnet.role }}" -{{ end }} - metadata: - name: "{{ .clusterId | lower }}-{{ .adapter.name }}-configmap" - namespace: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" - labels: - app.kubernetes.io/component: adapter-task-config - app.kubernetes.io/instance: "{{ .adapter.name }}" - app.kubernetes.io/name: cl-maestro - app.kubernetes.io/version: 1.0.0 - app.kubernetes.io/transport: maestro - annotations: - hyperfleet.io/generation: "{{ .generation }}" + - apiVersion: v1 + kind: Namespace + metadata: + name: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" + labels: + app.kubernetes.io/component: adapter-task-config + app.kubernetes.io/instance: "{{ .adapter.name }}" + app.kubernetes.io/name: cl-maestro + app.kubernetes.io/transport: maestro + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" + annotations: + hyperfleet.io/generation: "{{ .generation }}" + - apiVersion: v1 + kind: ConfigMap + data: + cluster_id: "{{ .clusterId }}" + cluster_name: "{{ .clusterName }}" + {{ if eq .platformType "gcp" }} +platform_tier: "cloud" + {{ else }} +platform_tier: "onprem" + {{ end }} + {{ range $i, $subnet := .subnets }} +subnet_{{ $subnet.id }}_name: "{{ $subnet.name }}" +subnet_{{ $subnet.id }}_cidr: "{{ $subnet.cidr }}" +subnet_{{ $subnet.id }}_role: "{{ $subnet.role }}" + {{ end }} +metadata: + name: "{{ .clusterId | lower }}-{{ .adapter.name }}-configmap" + namespace: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" + labels: + app.kubernetes.io/component: adapter-task-config + app.kubernetes.io/instance: "{{ .adapter.name }}" + app.kubernetes.io/name: cl-maestro + app.kubernetes.io/version: 1.0.0 + app.kubernetes.io/transport: maestro + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" + annotations: + hyperfleet.io/generation: "{{ .generation }}" - # ============================================================================ - # Delete Options - How resources should be removed - # ============================================================================ - deleteOption: - # Propagation policy for resource deletion - # - "Foreground": Wait for dependent resources to be deleted first - # - "Background": Delete immediately, let cluster handle dependents - # - "Orphan": Leave resources on cluster when ManifestWork is deleted - propagationPolicy: "Foreground" +# ============================================================================ +# Delete Options - How resources should be removed +# ============================================================================ +deleteOption: + # Propagation policy for resource deletion + # - "Foreground": Wait for dependent resources to be deleted first + # - "Background": Delete immediately, let cluster handle dependents + # - "Orphan": Leave resources on cluster when ManifestWork is deleted + propagationPolicy: "Foreground" - # Grace period for graceful deletion (seconds) - gracePeriodSeconds: 30 + # Grace period for graceful deletion (seconds) + gracePeriodSeconds: 30 - # ============================================================================ - # Manifest Configurations - Per-resource settings for update and feedback - # ============================================================================ - manifestConfigs: - - resourceIdentifier: - group: "" # Core API group (empty for v1 resources) - resource: "namespaces" # Resource type - name: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" # Specific resource name - updateStrategy: - type: "ServerSideApply" # Use server-side apply for namespaces - feedbackRules: - - type: "JSONPaths" # Use JSON path expressions for status feedback - jsonPaths: - - name: "phase" - path: ".status.phase" - # ======================================================================== - # Configuration for ConfigMap resources - # ======================================================================== - - resourceIdentifier: - group: "" # Core API group (empty for v1 resources) - resource: "configmaps" # Resource type - name: "{{ .clusterId | lower }}-{{ .adapter.name }}-configmap" # Specific resource name - namespace: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" - updateStrategy: - type: "ServerSideApply" # Use server-side apply for namespaces - serverSideApply: - fieldManager: "cl-maestro" # Field manager name for conflict resolution - force: false # Don't force conflicts (fail on conflicts) - feedbackRules: - - type: "JSONPaths" # Use JSON path expressions for status feedback - jsonPaths: - - name: "data" - path: ".data" - - name: "resourceVersion" - path: ".metadata.resourceVersion" +# ============================================================================ +# Manifest Configurations - Per-resource settings for update and feedback +# ============================================================================ +manifestConfigs: + - resourceIdentifier: + group: "" # Core API group (empty for v1 resources) + resource: "namespaces" # Resource type + name: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" # Specific resource name + updateStrategy: + type: "ServerSideApply" # Use server-side apply for namespaces + feedbackRules: + - type: "JSONPaths" # Use JSON path expressions for status feedback + jsonPaths: + - name: "phase" + path: ".status.phase" + # ======================================================================== + # Configuration for ConfigMap resources + # ======================================================================== + - resourceIdentifier: + group: "" # Core API group (empty for v1 resources) + resource: "configmaps" # Resource type + name: "{{ .clusterId | lower }}-{{ .adapter.name }}-configmap" # Specific resource name + namespace: "{{ .clusterId | lower }}-{{ .adapter.name }}-namespace" + updateStrategy: + type: "ServerSideApply" # Use server-side apply for namespaces + serverSideApply: + fieldManager: "cl-maestro" # Field manager name for conflict resolution + force: false # Don't force conflicts (fail on conflicts) + feedbackRules: + - type: "JSONPaths" # Use JSON path expressions for status feedback + jsonPaths: + - name: "data" + path: ".data" + - name: "resourceVersion" + path: ".metadata.resourceVersion" diff --git a/helmfile/configs/e2e/adapters/cl-namespace/adapter-task-config.yaml b/helmfile/configs/e2e/adapters/cl-namespace/adapter-task-config.yaml index fc519bd..107a049 100644 --- a/helmfile/configs/e2e/adapters/cl-namespace/adapter-task-config.yaml +++ b/helmfile/configs/e2e/adapters/cl-namespace/adapter-task-config.yaml @@ -6,11 +6,10 @@ params: source: "event.id" type: "string" required: true - - name: "testRunId" - source: "env.TEST_RUN_ID" + - name: "e2eRunId" + source: "env.E2E_RUN_ID" type: "string" required: false - default: "TEST_RUN_ID" - name: "ci" source: "env.CI" type: "string" @@ -64,7 +63,7 @@ resources: labels: hyperfleet.io/cluster-id: "{{ .clusterId }}" hyperfleet.io/cluster-name: "{{ .clusterName }}" - e2e.hyperfleet.io/test-run-id: "{{ .testRunId }}" + e2e.hyperfleet.io/run-id: "{{ .e2eRunId }}" e2e.hyperfleet.io/ci: "{{ .ci }}" e2e.hyperfleet.io/managed-by: "test-framework" annotations: diff --git a/helmfile/helmfile.yaml.gotmpl b/helmfile/helmfile.yaml.gotmpl index 4852c35..3e56254 100644 --- a/helmfile/helmfile.yaml.gotmpl +++ b/helmfile/helmfile.yaml.gotmpl @@ -27,6 +27,9 @@ environments: - projectId: {{ env "PROJECT_ID" | default "hcm-hyperfleet" }} brokerType: googlepubsub serviceType: {{ env "API_SERVICE_TYPE" | default "LoadBalancer" }} + e2eRunId: {{ env "E2E_RUN_ID" }} + labels: + e2e.hyperfleet.io/run-id: {{ env "E2E_RUN_ID" }} - environments/e2e-gcp/adapter-configs.yaml.gotmpl - environments/e2e-gcp/sentinel-configs.yaml e2e-kind: diff --git a/helmfile/values/base-adapter.yaml.gotmpl b/helmfile/values/base-adapter.yaml.gotmpl index 3600936..a4e14b8 100644 --- a/helmfile/values/base-adapter.yaml.gotmpl +++ b/helmfile/values/base-adapter.yaml.gotmpl @@ -23,6 +23,12 @@ broker: rabbitmq: url: {{ env "RABBITMQ_URL" | default "amqp://guest:guest@rabbitmq:5672" }} {{ end }} + +{{- if hasKey .Values "labels" }} +labels: + {{- toYaml .Values.labels | nindent 2 }} +{{- end }} + env: - name: SIMULATE_RESULT value: success @@ -30,3 +36,7 @@ env: valueFrom: fieldRef: fieldPath: metadata.namespace + {{- if hasKey .Values "e2eRunId" }} + - name: E2E_RUN_ID + value: {{ .Values.e2eRunId | quote }} + {{- end }} diff --git a/helmfile/values/base-api.yaml.gotmpl b/helmfile/values/base-api.yaml.gotmpl index efe8f09..ec1ecf1 100644 --- a/helmfile/values/base-api.yaml.gotmpl +++ b/helmfile/values/base-api.yaml.gotmpl @@ -23,4 +23,9 @@ config: {{- if eq .resourceType "nodepools" }} - {{ .name }} {{- end }} - {{- end }} \ No newline at end of file + {{- end }} + +{{- if hasKey .Values "labels" }} +labels: + {{- toYaml .Values.labels | nindent 2 }} +{{- end }} \ No newline at end of file diff --git a/helmfile/values/base-sentinel.yaml.gotmpl b/helmfile/values/base-sentinel.yaml.gotmpl index 4c1df37..78abad8 100644 --- a/helmfile/values/base-sentinel.yaml.gotmpl +++ b/helmfile/values/base-sentinel.yaml.gotmpl @@ -22,3 +22,8 @@ broker: rabbitmq: url: {{ env "RABBITMQ_URL" | default "amqp://guest:guest@rabbitmq:5672" }} {{ end }} + +{{- if hasKey .Values "labels" }} +labels: + {{- toYaml .Values.labels | nindent 2 }} +{{- end }} \ No newline at end of file