Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 64 additions & 14 deletions helm/adapter1/adapter-task-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ preconditions:
field: "name"
- name: "generation"
field: "generation"
- name: "is_deleting"
expression: "clusterStatus.?deleted_time.hasValue()"
- name: "clusterNotReady"
expression: |
status.conditions.filter(c, c.type == "Ready").size() > 0
Expand All @@ -43,9 +45,9 @@ preconditions:
)).getSeconds() > 300

- name: "validationCheck"
# Precondition passes if cluster is NOT Ready OR if cluster is Ready and stable for >300 seconds since last transition (enables self-healing)
# Precondition passes if cluster is NOT Ready OR if cluster is Ready and stable for >300 seconds since last transition (enables self-healing) OR if cluster is being deleted
expression: |
clusterNotReady || clusterReadyTTL
clusterNotReady || clusterReadyTTL || is_deleting

# Resources with valid K8s manifests
resources:
Expand All @@ -69,12 +71,21 @@ resources:
app.kubernetes.io/transport: kubernetes
hyperfleet.io/cluster-id: "{{ .clusterId }}"
hyperfleet.io/cluster-name: "{{ .clusterName }}"
annotations:
hyperfleet.io/generation: "{{ .generation }}"
discovery:
namespace: "{{ .namespace }}"
by_selectors:
label_selector:
hyperfleet.io/cluster-id: "{{ .clusterId }}"
hyperfleet.io/cluster-name: "{{ .clusterName }}"
lifecycle:
delete:
# Background propagation is appropriate for simple ConfigMap resources
# without nested dependencies - allows faster deletion without waiting
propagationPolicy: "Background"
when:
expression: "is_deleting"

# Post-processing with valid CEL expressions
# This example contains multiple resources, we will only report on the conditions of the jobNamespace not to overcomplicate the example
Expand All @@ -88,30 +99,42 @@ post:
- type: "Applied"
status:
expression: |
has(resources.resource0.metadata.creationTimestamp) ? "True" : "False"
is_deleting
Copy link
Copy Markdown
Contributor

@rh-amarin rh-amarin Apr 30, 2026

Choose a reason for hiding this comment

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

Being in deletion phase is not a direct indication of Applied not being True

The natural condition is still the resource being found in the discovery phase IMO

It wold be the same for reason and the Available condition values

? "False"
: (resources.?resource0.hasValue() ? "True" : "False")
reason:
expression: |
has(resources.resource0.metadata.creationTimestamp) ? "ConfigMapApplied" : "ConfigMapPending"
is_deleting
? "ResourceDeleted"
: (resources.?resource0.hasValue() ? "ConfigMapApplied" : "ConfigMapPending")
message:
expression: |
has(resources.resource0.metadata.creationTimestamp)
? "ConfigMap has been applied correctly"
: "ConfigMap is pending to be applied"
is_deleting
? "ConfigMap has been deleted"
: (resources.?resource0.hasValue()
? "ConfigMap has been applied correctly"
: "ConfigMap is pending to be applied")
# Available: Check job status conditions
- type: "Available"
status:
expression: |
has(resources.resource0.data.cluster_id) ? "True" : "False"
is_deleting
? "False"
: (resources.?resource0.?data.?cluster_id.hasValue() ? "True" : "False")
reason:
expression: |
has(resources.resource0.data.cluster_id)
? "ConfigMap data available"
: "ConfigMap data not yet available"
is_deleting
? "ResourceDeleted"
: (resources.?resource0.?data.?cluster_id.hasValue()
? "ConfigMapDataAvailable"
: "ConfigMapDataNotYetAvailable")
message:
expression: |
has(resources.resource0.data.cluster_id)
? "ConfigMap data available"
: "ConfigMap data not yet available"
is_deleting
? "ConfigMap data no longer available"
: (resources.?resource0.?data.?cluster_id.hasValue()
? "ConfigMap data available"
: "ConfigMap data not yet available")
# Health: Adapter execution status (runtime)
- type: "Health"
status:
Expand All @@ -123,6 +146,33 @@ post:
message:
expression: |
adapter.?errorMessage.orValue("") != "" ? adapter.?errorMessage.orValue("") : "All adapter operations completed successfully"
# Finalized: Deletion lifecycle completion
- type: "Finalized"
status:
expression: |
!is_deleting
? "False"
: (!resources.?resource0.hasValue()
? "True"
: "False")
reason:
expression: |
!is_deleting
? "ResourceActive"
: (!resources.?resource0.hasValue()
? "CleanupConfirmed"
: (adapter.?executionStatus.orValue("") == "failed"
? "CleanupFailed"
: "CleanupInProgress"))
message:
expression: |
!is_deleting
? "Resource is active, not scheduled for deletion"
: (!resources.?resource0.hasValue()
? "All resources deleted successfully"
: (adapter.?executionStatus.orValue("") == "failed"
? "Deletion failed during adapter execution"
: "Deletion in progress"))
# Event generation ID metadata field needs to use expression to avoid interpolation issues
observed_generation:
expression: "generation"
Expand Down
138 changes: 103 additions & 35 deletions helm/adapter2/adapter-task-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ preconditions:
field: "generation"
- name: "timestamp"
field: "created_time"
- name: "is_deleting"
expression: "clusterStatus.?deleted_time.hasValue()"
- name: "readyConditionStatus"
expression: |
status.conditions.filter(c, c.type == "Ready").size() > 0
Expand All @@ -39,16 +41,11 @@ preconditions:
- name: "placementClusterName"
expression: "\"cluster1\"" # TBC coming from placement adapter

# Structured conditions with valid operators
conditions:
- field: "readyConditionStatus"
operator: "equals"
value: "False"

- name: "validationCheck"
# Valid CEL expression
# Precondition passes if cluster is NOT Ready (readyConditionStatus == "False") OR if cluster is being deleted
# Note: Unlike adapter1/adapter3, this adapter does not implement self-healing TTL checks
expression: |
readyConditionStatus == "False"
readyConditionStatus == "False" || is_deleting

# Resources with valid K8s manifests
resources:
Expand Down Expand Up @@ -208,6 +205,15 @@ resources:
discovery:
by_name: "{{ .clusterId | lower }}-{{ .adapter.name }}-configmap"

# Deletion lifecycle - ManifestWork deletion cascades to nested resources
lifecycle:
delete:
# Foreground propagation ensures nested resources (namespace, configmap) are deleted
# before the parent ManifestWork is removed, preventing orphaned resources
propagationPolicy: "Foreground"
when:
expression: "is_deleting"

post:
payloads:
- name: "statusPayload"
Expand All @@ -218,47 +224,75 @@ post:
- type: "Applied"
status:
expression: |
has(resources.resource0) && has(resources.resource0.status) && has(resources.resource0.status.conditions) && resources.resource0.status.conditions.filter(c, has(c.type) && c.type == "Applied").size() > 0 ? resources.resource0.status.conditions.filter(c, c.type == "Applied")[0].status : "False"
!is_deleting
? (resources.?resource0.hasValue() && has(resources.resource0.status) && has(resources.resource0.status.conditions) && resources.resource0.status.conditions.filter(c, has(c.type) && c.type == "Applied").size() > 0 ? resources.resource0.status.conditions.filter(c, c.type == "Applied")[0].status : "False")
: "False"
reason:
expression: |
has(resources.resource0) && has(resources.resource0.status) && has(resources.resource0.status.conditions) && resources.resource0.status.conditions.filter(c, has(c.type) && c.type == "Applied").size() > 0 ? resources.resource0.status.conditions.filter(c, c.type == "Applied")[0].reason : "ManifestWorkNotDiscovered"
!is_deleting
? (resources.?resource0.hasValue() && has(resources.resource0.status) && has(resources.resource0.status.conditions) && resources.resource0.status.conditions.filter(c, has(c.type) && c.type == "Applied").size() > 0 ? resources.resource0.status.conditions.filter(c, c.type == "Applied")[0].reason : "ManifestWorkNotDiscovered")
: (!resources.?resource0.hasValue()
? "ResourceDeleted"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tip

nit — non-blocking suggestion

Category: Inconsistency

During deletion, adapter2 reports granular reasons for Applied/Available ("ResourceDeleted" / "DeletionFailed" / "DeletionInProgress"), but adapter1/adapter3 always report just "ResourceDeleted" regardless of actual deletion state. Since the PR title is "standardize adapter conditions," the reasons should be consistent across all three adapters.

If you keep the is_deleting wrapper on Applied/Available (see @rh-amarin's comment above), consider making adapter1/3 match adapter2's granularity — or simplifying adapter2 to match adapter1/3. If you remove the wrapper per Angel's suggestion, this resolves naturally.

: (adapter.?executionStatus.orValue("") == "failed"
? "DeletionFailed"
: "DeletionInProgress"))
message:
expression: |
has(resources.resource0) && has(resources.resource0.status) && has(resources.resource0.status.conditions) && resources.resource0.status.conditions.filter(c, has(c.type) && c.type == "Applied").size() > 0 ? resources.resource0.status.conditions.filter(c, c.type == "Applied")[0].message : "ManifestWork not discovered from Maestro or no Applied condition"
!is_deleting
? (resources.?resource0.hasValue() && has(resources.resource0.status) && has(resources.resource0.status.conditions) && resources.resource0.status.conditions.filter(c, has(c.type) && c.type == "Applied").size() > 0 ? resources.resource0.status.conditions.filter(c, c.type == "Applied")[0].message : "ManifestWork not discovered from Maestro or no Applied condition")
: (!resources.?resource0.hasValue()
? "ManifestWork deleted"
: (adapter.?executionStatus.orValue("") == "failed"
? "Deletion failed during adapter execution"
: "ManifestWork deletion in progress"))

# Available: Check if nested discovered manifests are available on the spoke cluster
# Each nested discovery is enriched with top-level "conditions" from status.resourceStatus.manifests[]
- type: "Available"
status:
expression: |
has(resources.namespace0) && has(resources.namespace0.conditions)
&& resources.namespace0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
&& has(resources.configmap0) && has(resources.configmap0.conditions)
&& resources.configmap0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "True"
: "False"
!is_deleting
? (resources.?namespace0.hasValue() && has(resources.namespace0.conditions)
&& resources.namespace0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
&& resources.?configmap0.hasValue() && has(resources.configmap0.conditions)
&& resources.configmap0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "True"
: "False")
: "False"
reason:
expression: |
!(has(resources.namespace0) && has(resources.namespace0.conditions))
? "NamespaceNotDiscovered"
: !resources.namespace0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "NamespaceNotAvailable"
: !(has(resources.configmap0) && has(resources.configmap0.conditions))
? "ConfigMapNotDiscovered"
: !resources.configmap0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "ConfigMapNotAvailable"
: "AllResourcesAvailable"
!is_deleting
? (!(resources.?namespace0.hasValue() && has(resources.namespace0.conditions))
? "NamespaceNotDiscovered"
: !resources.namespace0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "NamespaceNotAvailable"
: !(resources.?configmap0.hasValue() && has(resources.configmap0.conditions))
? "ConfigMapNotDiscovered"
: !resources.configmap0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "ConfigMapNotAvailable"
: "AllResourcesAvailable")
: (!resources.?namespace0.hasValue() && !resources.?configmap0.hasValue()
? "ResourceDeleted"
: (adapter.?executionStatus.orValue("") == "failed"
? "DeletionFailed"
: "DeletionInProgress"))
message:
expression: |
!(has(resources.namespace0) && has(resources.namespace0.conditions))
? "Namespace not discovered from ManifestWork"
: !resources.namespace0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "Namespace not yet available on spoke cluster"
: !(has(resources.configmap0) && has(resources.configmap0.conditions))
? "ConfigMap not discovered from ManifestWork"
: !resources.configmap0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "ConfigMap not yet available on spoke cluster"
: "All manifests (namespace, configmap) are available on spoke cluster"
!is_deleting
? (!(resources.?namespace0.hasValue() && has(resources.namespace0.conditions))
? "Namespace not discovered from ManifestWork"
: !resources.namespace0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "Namespace not yet available on spoke cluster"
: !(resources.?configmap0.hasValue() && has(resources.configmap0.conditions))
? "ConfigMap not discovered from ManifestWork"
: !resources.configmap0.conditions.exists(c, has(c.type) && c.type == "Available" && has(c.status) && c.status == "True")
? "ConfigMap not yet available on spoke cluster"
: "All manifests (namespace, configmap) are available on spoke cluster")
: (!resources.?namespace0.hasValue() && !resources.?configmap0.hasValue()
? "Nested resources deleted"
: (adapter.?executionStatus.orValue("") == "failed"
? "Deletion failed during adapter execution"
: "Nested resource deletion in progress"))

# Health: Adapter execution status — surfaces errors from any phase
- type: "Health"
Expand Down Expand Up @@ -288,6 +322,40 @@ post:
? "Resources skipped: " + adapter.?skipReason.orValue("unknown reason")
: "Adapter execution completed successfully"

# Finalized: Deletion lifecycle completion
- type: "Finalized"
status:
expression: |
!is_deleting
? "False"
: (!resources.?resource0.hasValue()
&& !resources.?namespace0.hasValue()
&& !resources.?configmap0.hasValue()
? "True"
: "False")
reason:
expression: |
!is_deleting
? "ResourceActive"
: (!resources.?resource0.hasValue()
&& !resources.?namespace0.hasValue()
&& !resources.?configmap0.hasValue()
? "CleanupConfirmed"
: (adapter.?executionStatus.orValue("") == "failed"
? "CleanupFailed"
: "CleanupInProgress"))
message:
expression: |
!is_deleting
? "Resource is active, not scheduled for deletion"
: (!resources.?resource0.hasValue()
&& !resources.?namespace0.hasValue()
&& !resources.?configmap0.hasValue()
? "ManifestWork and all nested resources deleted successfully"
: (adapter.?executionStatus.orValue("") == "failed"
? "Deletion failed during adapter execution"
: "Deletion in progress"))

Comment thread
coderabbitai[bot] marked this conversation as resolved.
observed_generation:
expression: "generation"
observed_time: "{{ now | date \"2006-01-02T15:04:05Z07:00\" }}"
Expand Down
Loading