From e865be9b8d44561e82280459e4037c341388057f Mon Sep 17 00:00:00 2001 From: Rafael Benevides Date: Fri, 10 Jul 2026 11:31:38 -0300 Subject: [PATCH] HYPERFLEET-1195 - docs: add when condition examples and documentation Add skipped-path example (adapter.resourcesSkipped) to the kubernetes example adapter, complementing the existing normal-path when gate. Demonstrates conditional payloads and post-actions for adapter authors. Enhance authoring guide with common when patterns table, guidance on combining when on payloads and post-actions, and cross-reference to the kubernetes example. --- .../kubernetes/adapter-task-config.yaml | 45 +++++++++++++++++++ docs/adapter-authoring-guide.md | 32 +++++++++++++ 2 files changed, 77 insertions(+) diff --git a/charts/examples/kubernetes/adapter-task-config.yaml b/charts/examples/kubernetes/adapter-task-config.yaml index 104f3694..94fbf8f4 100644 --- a/charts/examples/kubernetes/adapter-task-config.yaml +++ b/charts/examples/kubernetes/adapter-task-config.yaml @@ -65,6 +65,8 @@ resources: post: payloads: - name: "clusterStatusPayload" + when: + expression: "!adapter.resourcesSkipped" build: adapter: "{{ .adapter.name }}" conditions: @@ -163,6 +165,38 @@ post: expression: "generation" observed_time: "{{ now | date \"2006-01-02T15:04:05Z07:00\" }}" + # Skipped path: preconditions not met — report simplified status without + # evaluating resources.* (which may not exist in this context) + - name: "skippedStatusPayload" + when: + expression: "adapter.resourcesSkipped" + build: + adapter: "{{ .adapter.name }}" + conditions: + - type: "Applied" + status: "False" + reason: "PreconditionsNotMet" + message: + expression: | + "Resources skipped: " + adapter.?skipReason.orValue("preconditions not met") + - type: "Available" + status: "False" + reason: "PreconditionsNotMet" + message: + expression: | + "Resources not available: " + adapter.?skipReason.orValue("preconditions not met") + - type: "Health" + status: "True" + reason: "NoErrors" + message: "Adapter is healthy, no work performed due to preconditions" + - type: "Finalized" + status: "False" + reason: "" + message: "" + observed_generation: + expression: "generation" + observed_time: "{{ now | date \"2006-01-02T15:04:05Z07:00\" }}" + post_actions: - name: "reportClusterStatus" when: @@ -174,3 +208,14 @@ post: - name: "Content-Type" value: "application/json" body: "{{ .clusterStatusPayload }}" + + - name: "reportClusterStatusSkipped" + when: + expression: "adapter.resourcesSkipped" + api_call: + method: "PUT" + url: "/clusters/{{ .clusterId }}/statuses" + headers: + - name: "Content-Type" + value: "application/json" + body: "{{ .skippedStatusPayload }}" diff --git a/docs/adapter-authoring-guide.md b/docs/adapter-authoring-guide.md index 203411fc..84d6ec2f 100644 --- a/docs/adapter-authoring-guide.md +++ b/docs/adapter-authoring-guide.md @@ -1227,6 +1227,38 @@ post: The `when` expression has access to the full execution context: all `adapter.*` metadata, extracted params, and `resources.*`. If `when` is omitted, the payload is always built (existing behavior). If the expression fails to parse or evaluate, the payload build is marked as **failed**. Evaluation order: payload `when` → build → post-action `when` → execute. Both gates are independent. +### Common `when` patterns + +| Pattern | Expression | Use case | +|---------|-----------|----------| +| Run when work was done | `!adapter.resourcesSkipped` | Most common — gate status reporting on whether resources were actually applied | +| Success-only | `adapter.?executionStatus.orValue('') == 'success'` | Run only when all phases succeeded | +| Failure-only | `adapter.?executionStatus.orValue('') != 'success'` | Send a different status report on failure | +| Deletion path | `is_deleting` | Run only during cluster deletion (requires `is_deleting` param) | +| Resource exists | `resources.?myResource.hasValue()` | Gate on whether a specific resource was discovered | + +#### Combining `when` on payloads and post-actions + +You can use `when` at both levels. A post-action that references a skipped payload is automatically skipped, so adding `when` to the post-action is redundant in that case. However, using both makes intent explicit in the config and avoids relying on the implicit auto-skip behavior: + +```yaml +post: + payloads: + - name: "statusPayload" + when: + expression: "!adapter.resourcesSkipped" # prevents CEL evaluation of missing resources.* + build: { ... } + + post_actions: + - name: "reportClusterStatus" + when: + expression: "!adapter.resourcesSkipped" # explicit gate — also auto-skipped via payload + api_call: + body: "{{ .statusPayload }}" +``` + +> For a complete working example of conditional payloads and post-actions, see the `adapter1` configuration in [hyperfleet-infra](https://github.com/openshift-hyperfleet/hyperfleet-infra/tree/main/helmfile/configs/base/adapters/adapter1/adapter-task-config.yaml). + ### Building payloads A payload is a JSON structure built from CEL expressions and Go Templates. Each field can be specified in three ways: