From 0d857338974f64a4133716c98c08b8c2d86b3a6b Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Thu, 9 Apr 2026 17:01:16 +0000 Subject: [PATCH 1/2] Fix namespace fallback in rendered resource operations Use Chainsaw's ephemeral test namespace as a fallback for rendered kubectl operations when a resource manifest omits metadata.namespace. This keeps cluster-scoped resources working as-is, fixes namespaced resources created in Chainsaw's generated namespace, and removes the import path's dependency on remotely fetched patch helpers for this flow. --- internal/templates/00-apply.yaml.tmpl | 33 +- internal/templates/01-update.yaml.tmpl | 94 +- internal/templates/02-import.yaml.tmpl | 182 ++- internal/templates/03-delete.yaml.tmpl | 69 +- internal/templates/renderer_test.go | 1519 +++++++++++++++++++++--- 5 files changed, 1662 insertions(+), 235 deletions(-) diff --git a/internal/templates/00-apply.yaml.tmpl b/internal/templates/00-apply.yaml.tmpl index bf07646..c53b732 100644 --- a/internal/templates/00-apply.yaml.tmpl +++ b/internal/templates/00-apply.yaml.tmpl @@ -32,17 +32,42 @@ spec: - apply: file: {{ .TestCase.TestDirectory }} - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -61,7 +86,7 @@ spec: {{- if eq $resource.KindGroup "secret." -}} {{continue}} {{- end }} - retry_annotate "${KUBECTL} annotate {{ if $resource.Namespace }}--namespace {{ $resource.Namespace }} {{ end }} {{ $resource.KindGroup }}/{{ $resource.Name }} upjet.upbound.io/test=true --overwrite" + retry_annotate "{{ $resource.Namespace }}" "{{ $resource.KindGroup }}/{{ $resource.Name }}" {{- end }} - name: Assert Status Conditions description: | diff --git a/internal/templates/01-update.yaml.tmpl b/internal/templates/01-update.yaml.tmpl index 49c6872..3c2d65c 100644 --- a/internal/templates/01-update.yaml.tmpl +++ b/internal/templates/01-update.yaml.tmpl @@ -20,16 +20,71 @@ spec: {{- end }} {{- if $resource.Root }} - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if [ "$verb" = "status-patch" ] && run_resource_status_patch "$namespace" "$resource" "$@"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + fi + if [ "$verb" != "status-patch" ] && run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -44,8 +99,8 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} --subresource=status patch {{ $resource.KindGroup }}/{{ $resource.Name }} --type=merge -p '{\"status\":{\"conditions\":[]}}'" - retry_kubectl "${KUBECTL} patch {{ $resource.KindGroup }}/{{ $resource.Name }} --type=merge -p '{\"spec\":{\"forProvider\":{{ $resource.UpdateParameter }}}}'" + retry_kubectl "{{ $resource.Namespace }}" "status-patch" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --type=merge -p '{"status":{"conditions":[]}}' + retry_kubectl "{{ $resource.Namespace }}" "patch" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --type=merge -p '{"spec":{"forProvider":{{ $resource.UpdateParameter }}}}' {{- end }} {{- end }} - name: Assert Updated Resource @@ -73,6 +128,33 @@ spec: status: "True" {{- end }} - script: - content: ${KUBECTL} get {{ if $resource.Namespace }}--namespace {{ $resource.Namespace }} {{ end }} {{ $resource.KindGroup }}/{{ $resource.Name }} -o=jsonpath='{.status.atProvider{{ $resource.UpdateAssertKey }}}' | grep -q "^{{ $resource.UpdateAssertValue }}$" + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) + content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_kubectl "{{ $resource.Namespace }}" "get" "{{ $resource.KindGroup }}/{{ $resource.Name }}" -o=jsonpath='{.status.atProvider{{ $resource.UpdateAssertKey }}}' | grep -q "^{{ $resource.UpdateAssertValue }}$" {{- end }} {{- end }} diff --git a/internal/templates/02-import.yaml.tmpl b/internal/templates/02-import.yaml.tmpl index 69f9e7f..4f97a16 100644 --- a/internal/templates/02-import.yaml.tmpl +++ b/internal/templates/02-import.yaml.tmpl @@ -17,15 +17,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -44,7 +73,7 @@ spec: {{- if eq $resource.KindGroup "secret." -}} {{continue}} {{- end }} - retry_kubectl "${KUBECTL} annotate {{ if $resource.Namespace }}--namespace {{ $resource.Namespace }} {{ end }} {{ $resource.KindGroup }}/{{ $resource.Name }} crossplane.io/paused=true --overwrite" + retry_kubectl "{{ $resource.Namespace }}" "annotate" "{{ $resource.KindGroup }}/{{ $resource.Name }}" crossplane.io/paused=true --overwrite {{- end }} PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then @@ -55,42 +84,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - {{- if not .TestCase.SkipWebhookCheck }} - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh - /tmp/check_endpoints.sh - sleep 10 - {{- end }} - {{- range $resource := .Resources }} - {{- if eq $resource.KindGroup "secret." -}} - {{continue}} - {{- end -}} - {{- if not $resource.SkipImport }} - {{- if not $resource.Namespace }} - /tmp/patch.sh {{ $resource.KindGroup }} {{ $resource.Name }} - {{- end }} - {{- if $resource.Namespace }} - /tmp/patch-ns.sh {{ $resource.KindGroup }} {{ $resource.Name }} {{ $resource.Namespace }} - {{- end }} - {{- end }} - {{- end }} + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -102,14 +195,35 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + {{- if not .TestCase.SkipWebhookCheck }} + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + /tmp/check_endpoints.sh + sleep 10 + {{- end }} + {{- range $resource := .Resources }} + {{- if eq $resource.KindGroup "secret." -}} + {{continue}} + {{- end -}} + {{- if not $resource.SkipImport }} + retry_patch_resource_for_import "{{ $resource.Namespace }}" "{{ $resource.KindGroup }}/{{ $resource.Name }}" + {{- end }} + {{- end }} {{- range $resource := .Resources }} {{- if eq $resource.KindGroup "secret." -}} {{continue}} {{- end }} - retry_kubectl "${KUBECTL} annotate {{ if $resource.Namespace }}--namespace {{ $resource.Namespace }} {{ end }} {{ $resource.KindGroup }}/{{ $resource.Name }} --all crossplane.io/paused=false --overwrite" + retry_kubectl "{{ $resource.Namespace }}" "annotate" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --all crossplane.io/paused=false --overwrite {{- end }} - name: Assert Status Conditions and IDs description: | diff --git a/internal/templates/03-delete.yaml.tmpl b/internal/templates/03-delete.yaml.tmpl index 57321e8..4ffe514 100644 --- a/internal/templates/03-delete.yaml.tmpl +++ b/internal/templates/03-delete.yaml.tmpl @@ -11,16 +11,45 @@ spec: description: Delete resources. If needs ordered deletion, the pre-delete scripts were used. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -42,11 +71,7 @@ spec: {{- if $resource.PreDeleteScriptPath }} {{ $resource.PreDeleteScriptPath }} {{- end }} - {{- if $resource.Namespace }} - retry_kubectl "${KUBECTL} delete {{ $resource.KindGroup }}/{{ $resource.Name }} --wait=false --namespace {{ $resource.Namespace }} --ignore-not-found" - {{- else }} - retry_kubectl "${KUBECTL} delete {{ $resource.KindGroup }}/{{ $resource.Name }} --wait=false --ignore-not-found" - {{- end }} + retry_kubectl "{{ $resource.Namespace }}" "delete" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --wait=false --ignore-not-found {{- if $resource.PostDeleteScriptPath }} {{ $resource.PostDeleteScriptPath }} {{- end }} @@ -59,8 +84,34 @@ spec: {{continue}} {{- end }} - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - ${KUBECTL} wait {{ if $resource.Namespace }}--namespace {{ $resource.Namespace }} {{ end }}--for=delete {{ $resource.KindGroup }}/{{ $resource.Name }} --timeout {{ $.TestCase.Timeout }} + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_kubectl "{{ $resource.Namespace }}" "wait" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --for=delete --timeout {{ $.TestCase.Timeout }} {{- end }} {{- if not .TestCase.OnlyCleanUptestResources }} - script: diff --git a/internal/templates/renderer_test.go b/internal/templates/renderer_test.go index c901546..90e543d 100644 --- a/internal/templates/renderer_test.go +++ b/internal/templates/renderer_test.go @@ -109,17 +109,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -134,7 +159,7 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -191,15 +216,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -214,7 +268,7 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" crossplane.io/paused=true --overwrite PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 0}]' @@ -224,28 +278,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh - /tmp/check_endpoints.sh - sleep 10 - /tmp/patch.sh s3.aws.upbound.io example-bucket + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -257,10 +389,22 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite" + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + /tmp/check_endpoints.sh + sleep 10 + retry_patch_resource_for_import "" "s3.aws.upbound.io/example-bucket" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" --all crossplane.io/paused=false --overwrite - name: Assert Status Conditions and IDs description: | Assert imported resources. Firstly check the status conditions. Then @@ -298,16 +442,45 @@ spec: description: Delete resources. If needs ordered deletion, the pre-delete scripts were used. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -322,13 +495,39 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} delete s3.aws.upbound.io/example-bucket --wait=false --ignore-not-found" + retry_kubectl "" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found - name: Assert Deletion description: Assert deletion of resources. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - ${KUBECTL} wait --for=delete s3.aws.upbound.io/example-bucket --timeout 10m0s + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_kubectl "" "wait" "s3.aws.upbound.io/example-bucket" --for=delete --timeout 10m0s - script: content: | ${KUBECTL} wait managed --all --for=delete --timeout -1s @@ -380,17 +579,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -405,7 +629,7 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -462,15 +686,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -485,7 +738,7 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" crossplane.io/paused=true --overwrite PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 0}]' @@ -495,28 +748,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh - /tmp/check_endpoints.sh - sleep 10 - /tmp/patch.sh s3.aws.upbound.io example-bucket + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -528,10 +859,22 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite" + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + /tmp/check_endpoints.sh + sleep 10 + retry_patch_resource_for_import "" "s3.aws.upbound.io/example-bucket" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" --all crossplane.io/paused=false --overwrite - name: Assert Status Conditions and IDs description: | Assert imported resources. Firstly check the status conditions. Then @@ -569,16 +912,45 @@ spec: description: Delete resources. If needs ordered deletion, the pre-delete scripts were used. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -593,13 +965,39 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} delete s3.aws.upbound.io/example-bucket --wait=false --ignore-not-found" + retry_kubectl "" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found - name: Assert Deletion description: Assert deletion of resources. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - ${KUBECTL} wait --for=delete s3.aws.upbound.io/example-bucket --timeout 10m0s + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_kubectl "" "wait" "s3.aws.upbound.io/example-bucket" --for=delete --timeout 10m0s - script: content: | ${KUBECTL} wait managed --all --for=delete --timeout -1s @@ -678,17 +1076,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -703,8 +1126,8 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" - retry_annotate "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" + retry_annotate "upbound-system" "cluster.gcp.platformref.upbound.io/test-cluster-claim" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -777,15 +1200,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -800,8 +1252,8 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite" - retry_kubectl "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim crossplane.io/paused=true --overwrite" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" crossplane.io/paused=true --overwrite + retry_kubectl "upbound-system" "annotate" "cluster.gcp.platformref.upbound.io/test-cluster-claim" crossplane.io/paused=true --overwrite PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 0}]' @@ -811,28 +1263,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh - /tmp/check_endpoints.sh - sleep 10 - /tmp/patch.sh s3.aws.upbound.io example-bucket + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -844,11 +1374,23 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite" - retry_kubectl "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim --all crossplane.io/paused=false --overwrite" + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + /tmp/check_endpoints.sh + sleep 10 + retry_patch_resource_for_import "" "s3.aws.upbound.io/example-bucket" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" --all crossplane.io/paused=false --overwrite + retry_kubectl "upbound-system" "annotate" "cluster.gcp.platformref.upbound.io/test-cluster-claim" --all crossplane.io/paused=false --overwrite - name: Assert Status Conditions and IDs description: | Assert imported resources. Firstly check the status conditions. Then @@ -886,16 +1428,45 @@ spec: description: Delete resources. If needs ordered deletion, the pre-delete scripts were used. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -910,19 +1481,71 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} delete s3.aws.upbound.io/example-bucket --wait=false --ignore-not-found" + retry_kubectl "" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found /tmp/bucket/post-delete.sh /tmp/claim/pre-delete.sh - retry_kubectl "${KUBECTL} delete cluster.gcp.platformref.upbound.io/test-cluster-claim --wait=false --namespace upbound-system --ignore-not-found" + retry_kubectl "upbound-system" "delete" "cluster.gcp.platformref.upbound.io/test-cluster-claim" --wait=false --ignore-not-found - name: Assert Deletion description: Assert deletion of resources. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - ${KUBECTL} wait --for=delete s3.aws.upbound.io/example-bucket --timeout 10m0s + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_kubectl "" "wait" "s3.aws.upbound.io/example-bucket" --for=delete --timeout 10m0s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - ${KUBECTL} wait --namespace upbound-system --for=delete cluster.gcp.platformref.upbound.io/test-cluster-claim --timeout 10m0s + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_kubectl "upbound-system" "wait" "cluster.gcp.platformref.upbound.io/test-cluster-claim" --for=delete --timeout 10m0s - script: content: | ${KUBECTL} wait managed --all --for=delete --timeout -1s @@ -1009,17 +1632,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -1034,7 +1682,7 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -1091,15 +1739,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -1114,7 +1791,7 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" crossplane.io/paused=true --overwrite PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 0}]' @@ -1124,28 +1801,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh - /tmp/check_endpoints.sh - sleep 10 - /tmp/patch.sh s3.aws.upbound.io example-bucket + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -1157,10 +1912,22 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite" + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + /tmp/check_endpoints.sh + sleep 10 + retry_patch_resource_for_import "" "s3.aws.upbound.io/example-bucket" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" --all crossplane.io/paused=false --overwrite - name: Assert Status Conditions and IDs description: | Assert imported resources. Firstly check the status conditions. Then @@ -1261,17 +2028,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -1286,8 +2078,8 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" - retry_annotate "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" + retry_annotate "upbound-system" "cluster.gcp.platformref.upbound.io/test-cluster-claim" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -1415,17 +2207,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -1440,8 +2257,8 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" - retry_annotate "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" + retry_annotate "upbound-system" "cluster.gcp.platformref.upbound.io/test-cluster-claim" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -1514,15 +2331,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -1537,8 +2383,8 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite" - retry_kubectl "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim crossplane.io/paused=true --overwrite" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" crossplane.io/paused=true --overwrite + retry_kubectl "upbound-system" "annotate" "cluster.gcp.platformref.upbound.io/test-cluster-claim" crossplane.io/paused=true --overwrite PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 0}]' @@ -1548,28 +2394,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh - /tmp/check_endpoints.sh - sleep 10 - /tmp/patch.sh s3.aws.upbound.io example-bucket + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -1581,11 +2505,23 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite" - retry_kubectl "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim --all crossplane.io/paused=false --overwrite" + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + /tmp/check_endpoints.sh + sleep 10 + retry_patch_resource_for_import "" "s3.aws.upbound.io/example-bucket" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" --all crossplane.io/paused=false --overwrite + retry_kubectl "upbound-system" "annotate" "cluster.gcp.platformref.upbound.io/test-cluster-claim" --all crossplane.io/paused=false --overwrite - name: Assert Status Conditions and IDs description: | Assert imported resources. Firstly check the status conditions. Then @@ -1669,17 +2605,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -1694,7 +2655,7 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim upjet.upbound.io/test=true --overwrite" + retry_annotate "upbound-system" "cluster.gcp.platformref.upbound.io/test-cluster-claim" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -1785,17 +2746,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -1810,8 +2796,8 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate --namespace upbound-system cluster.gcp.platformref.upbound.io/test-cluster-claim upjet.upbound.io/test=true --overwrite" - retry_annotate "${KUBECTL} annotate xnetwork.gcp.platformref.upbound.io/test-network-xr upjet.upbound.io/test=true --overwrite" + retry_annotate "upbound-system" "cluster.gcp.platformref.upbound.io/test-cluster-claim" + retry_annotate "" "xnetwork.gcp.platformref.upbound.io/test-network-xr" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -1921,17 +2907,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -1946,7 +2957,7 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -2010,17 +3021,42 @@ spec: - apply: file: /tmp/test-input.yaml - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | echo "Running annotation script with retry logic" + annotate_resource() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ]; then + ${KUBECTL} annotate --namespace "$namespace" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + if ${KUBECTL} annotate "$resource" upjet.upbound.io/test=true --overwrite; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} annotate --namespace "$CHAINSAW_NAMESPACE" "$resource" upjet.upbound.io/test=true --overwrite + return $? + fi + + return 1 + } + retry_annotate() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local resource="$2" while [ $attempt -le $max_attempts ]; do - echo "Annotation attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Annotation attempt $attempt/$max_attempts for: $resource" + if annotate_resource "$namespace" "$resource"; then echo "Annotation successful on attempt $attempt" return 0 else @@ -2035,7 +3071,7 @@ spec: echo "Annotation failed after $max_attempts attempts" return 1 } - retry_annotate "${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite" + retry_annotate "" "s3.aws.upbound.io/example-bucket" - name: Assert Status Conditions description: | Assert applied resources. First, run the pre-assert script if exists. @@ -2071,15 +3107,44 @@ spec: uptest-old-id annotation. try: - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -2094,7 +3159,7 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" crossplane.io/paused=true --overwrite PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) if [ -n "$PROVIDER_CONFIGS" ]; then echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 0}]' @@ -2104,25 +3169,106 @@ spec: - sleep: duration: 10s - script: + env: + - name: CHAINSAW_NAMESPACE + value: ($namespace) content: | - PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) - if [ -n "$PROVIDER_CONFIGS" ]; then - echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' - else - echo "No provider DeploymentRuntimeConfigs found to scale up" - fi - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh - curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch-ns.sh -o /tmp/patch-ns.sh && chmod +x /tmp/patch-ns.sh - /tmp/patch.sh s3.aws.upbound.io example-bucket + run_resource_kubectl() { + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 + + if [ -n "$namespace" ]; then + ${KUBECTL} "$verb" --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} "$verb" "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} "$verb" --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + run_resource_status_patch() { + local namespace="$1" + local resource="$2" + shift 2 + + if [ -n "$namespace" ]; then + ${KUBECTL} --subresource=status patch --namespace "$namespace" "$resource" "$@" + return $? + fi + + if ${KUBECTL} --subresource=status patch "$resource" "$@"; then + return 0 + fi + + if [ -n "$CHAINSAW_NAMESPACE" ]; then + ${KUBECTL} --subresource=status patch --namespace "$CHAINSAW_NAMESPACE" "$resource" "$@" + return $? + fi + + return 1 + } + + patch_resource_for_import() { + local namespace="$1" + local resource="$2" + local old_id + + if ! run_resource_status_patch "$namespace" "$resource" --type=merge -p '{"status":{"conditions":[]}}'; then + return 1 + fi + + old_id=$(run_resource_kubectl "$namespace" get "$resource" -o=jsonpath='{.status.atProvider.id}') || return 1 + run_resource_kubectl "$namespace" annotate "$resource" "uptest-old-id=$old_id" --overwrite + } + + retry_patch_resource_for_import() { + local max_attempts=10 + local delay=5 + local attempt=1 + local namespace="$1" + local resource="$2" + + while [ $attempt -le $max_attempts ]; do + echo "Kubectl attempt $attempt/$max_attempts for: import $resource" + if patch_resource_for_import "$namespace" "$resource"; then + echo "Kubectl operation successful on attempt $attempt" + return 0 + else + echo "Kubectl operation failed on attempt $attempt" + if [ $attempt -lt $max_attempts ]; then + echo "Retrying in ${delay}s..." + sleep $delay + fi + ((attempt++)) + fi + done + + echo "Kubectl operation failed after $max_attempts attempts" + return 1 + } + retry_kubectl() { local max_attempts=10 local delay=5 local attempt=1 - local cmd="$1" + local namespace="$1" + local verb="$2" + local resource="$3" + shift 3 while [ $attempt -le $max_attempts ]; do - echo "Kubectl attempt $attempt/$max_attempts for: $cmd" - if eval "$cmd"; then + echo "Kubectl attempt $attempt/$max_attempts for: $verb $resource" + if run_resource_kubectl "$namespace" "$verb" "$resource" "$@"; then echo "Kubectl operation successful on attempt $attempt" return 0 else @@ -2134,10 +3280,19 @@ spec: ((attempt++)) fi done + echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite" + + PROVIDER_CONFIGS=$(${KUBECTL} get deploymentruntimeconfig --no-headers -o custom-columns=":metadata.name" | grep "provider-" || true) + if [ -n "$PROVIDER_CONFIGS" ]; then + echo "$PROVIDER_CONFIGS" | xargs ${KUBECTL} patch deploymentruntimeconfig --type='json' -p='[{"op": "replace", "path": "/spec/deploymentTemplate/spec/replicas", "value": 1}]' + else + echo "No provider DeploymentRuntimeConfigs found to scale up" + fi + retry_patch_resource_for_import "" "s3.aws.upbound.io/example-bucket" + retry_kubectl "" "annotate" "s3.aws.upbound.io/example-bucket" --all crossplane.io/paused=false --overwrite - name: Assert Status Conditions and IDs description: | Assert imported resources. Firstly check the status conditions. Then From 1b9c9c8edfebe7ffaff1f82bc6a721daeddcaebb Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Thu, 9 Apr 2026 18:15:36 +0000 Subject: [PATCH 2/2] fix(delete): resolve namespace fallback before delete --- internal/templates/03-delete.yaml.tmpl | 17 +++++++- internal/templates/renderer_test.go | 54 ++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/internal/templates/03-delete.yaml.tmpl b/internal/templates/03-delete.yaml.tmpl index 4ffe514..24ae30b 100644 --- a/internal/templates/03-delete.yaml.tmpl +++ b/internal/templates/03-delete.yaml.tmpl @@ -64,6 +64,20 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } + + resolve_delete_namespace() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ] || [ -z "$CHAINSAW_NAMESPACE" ]; then + printf '%s' "$namespace" + return 0 + fi + + if ${KUBECTL} get --namespace "$CHAINSAW_NAMESPACE" "$resource" >/dev/null 2>&1; then + printf '%s' "$CHAINSAW_NAMESPACE" + fi + } {{- range $resource := .Resources }} {{- if eq $resource.KindGroup "secret." -}} {{continue}} @@ -71,7 +85,8 @@ spec: {{- if $resource.PreDeleteScriptPath }} {{ $resource.PreDeleteScriptPath }} {{- end }} - retry_kubectl "{{ $resource.Namespace }}" "delete" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --wait=false --ignore-not-found + resolved_namespace=$(resolve_delete_namespace "{{ $resource.Namespace }}" "{{ $resource.KindGroup }}/{{ $resource.Name }}") + retry_kubectl "$resolved_namespace" "delete" "{{ $resource.KindGroup }}/{{ $resource.Name }}" --wait=false --ignore-not-found {{- if $resource.PostDeleteScriptPath }} {{ $resource.PostDeleteScriptPath }} {{- end }} diff --git a/internal/templates/renderer_test.go b/internal/templates/renderer_test.go index 90e543d..a705acf 100644 --- a/internal/templates/renderer_test.go +++ b/internal/templates/renderer_test.go @@ -495,7 +495,22 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found + + resolve_delete_namespace() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ] || [ -z "$CHAINSAW_NAMESPACE" ]; then + printf '%s' "$namespace" + return 0 + fi + + if ${KUBECTL} get --namespace "$CHAINSAW_NAMESPACE" "$resource" >/dev/null 2>&1; then + printf '%s' "$CHAINSAW_NAMESPACE" + fi + } + resolved_namespace=$(resolve_delete_namespace "" "s3.aws.upbound.io/example-bucket") + retry_kubectl "$resolved_namespace" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found - name: Assert Deletion description: Assert deletion of resources. try: @@ -965,7 +980,22 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found + + resolve_delete_namespace() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ] || [ -z "$CHAINSAW_NAMESPACE" ]; then + printf '%s' "$namespace" + return 0 + fi + + if ${KUBECTL} get --namespace "$CHAINSAW_NAMESPACE" "$resource" >/dev/null 2>&1; then + printf '%s' "$CHAINSAW_NAMESPACE" + fi + } + resolved_namespace=$(resolve_delete_namespace "" "s3.aws.upbound.io/example-bucket") + retry_kubectl "$resolved_namespace" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found - name: Assert Deletion description: Assert deletion of resources. try: @@ -1481,10 +1511,26 @@ spec: echo "Kubectl operation failed after $max_attempts attempts" return 1 } - retry_kubectl "" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found + + resolve_delete_namespace() { + local namespace="$1" + local resource="$2" + + if [ -n "$namespace" ] || [ -z "$CHAINSAW_NAMESPACE" ]; then + printf '%s' "$namespace" + return 0 + fi + + if ${KUBECTL} get --namespace "$CHAINSAW_NAMESPACE" "$resource" >/dev/null 2>&1; then + printf '%s' "$CHAINSAW_NAMESPACE" + fi + } + resolved_namespace=$(resolve_delete_namespace "" "s3.aws.upbound.io/example-bucket") + retry_kubectl "$resolved_namespace" "delete" "s3.aws.upbound.io/example-bucket" --wait=false --ignore-not-found /tmp/bucket/post-delete.sh /tmp/claim/pre-delete.sh - retry_kubectl "upbound-system" "delete" "cluster.gcp.platformref.upbound.io/test-cluster-claim" --wait=false --ignore-not-found + resolved_namespace=$(resolve_delete_namespace "upbound-system" "cluster.gcp.platformref.upbound.io/test-cluster-claim") + retry_kubectl "$resolved_namespace" "delete" "cluster.gcp.platformref.upbound.io/test-cluster-claim" --wait=false --ignore-not-found - name: Assert Deletion description: Assert deletion of resources. try: