Skip to content

OCPBUGS-63720: orphan machines when managed identity is invalid on clus… - #8296

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
patilsuraj767:fix-OCPBUGS-63720
Jul 13, 2026
Merged

OCPBUGS-63720: orphan machines when managed identity is invalid on clus…#8296
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
patilsuraj767:fix-OCPBUGS-63720

Conversation

@patilsuraj767

@patilsuraj767 patilsuraj767 commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

…ter deletion

Summary

When a customer deletes a managed identity required for cleaning up resources in the managed resource group, HyperShift will now skip deletion of those Azure machines and allow the ARO cluster service to handle cleanup using a special Azure 1P application identity.

Fixes: OCPBUGS-63720

Changes

  • Implement DeleteOrphanedMachines for the Azure platform to satisfy the OrphanDeleter interface by inspecting each AzureMachine's own status conditions for Ready=False with Reason=DeletionFailed, rather than relying on HostedCluster-level credential conditions
  • Add a deletionFailedThreshold (10 minutes) based on the machine's DeletionTimestamp to avoid orphaning machines that hit transient cloud API failures
  • Add hasDeletionFailedCondition helper to check individual AzureMachine status conditions
  • Add unit tests covering all relevant scenarios

How it works

  • DeleteOrphanedMachines inspects each AzureMachine individually rather than relying on HostedCluster-level conditions:
  • If ManagedIdentities is nil → return early (not a managed-identity cluster)
  • List all AzureMachine resources in the control plane namespace
  • For each machine, check three conditions before orphaning:
  • The machine has a non-zero DeletionTimestamp (it is being deleted)
  • The DeletionTimestamp is older than 10 minutes (rules out transient failures)
  • The machine has a Ready=False condition with Reason=DeletionFailed (the CAPZ provider explicitly failed to delete the VM, e.g., due to invalid or expired credentials)
  • If all three conditions are met, strip the azuremachine.infrastructure.cluster.x-k8s.io finalizer and log that the machine was orphaned

Testing

Unit tests cover:

  • ManagedIdentities is nil → no orphaning (early return)
  • No machines in namespace → no-op
  • Machine with stale DeletionTimestamp and DeletionFailed condition → finalizer removed
  • Machine with recent DeletionTimestamp and DeletionFailed condition → finalizer not removed (within threshold)
  • Machine with stale DeletionTimestamp but no DeletionFailed condition → finalizer not removed
  • Machine not pending deletion → no modification regardless of conditions

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci openshift-ci Bot added do-not-merge/needs-area needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Apr 21, 2026
@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds Azure credential validation and orphaned-machine cleanup to the Azure platform code. Introduces ValidCredentials(hc *hyperv1.HostedCluster) bool to detect invalid Azure credentials from HostedCluster status conditions. Adds Azure.DeleteOrphanedMachines(ctx, c, hc, controlPlaneNamespace) error which returns early if managed identities are unset or credentials are valid; otherwise it lists capiav2 AzureMachine objects in the control plane namespace and, for machines with a non-nil DeletionTimestamp, clears Finalizers and updates the resource, aggregating per-machine errors. Unit tests for both functions were added.

Sequence Diagram(s)

sequenceDiagram
    participant Controller as Azure.DeleteOrphanedMachines
    participant HostedCluster as HostedCluster.Status
    participant K8sAPI as Kubernetes API
    participant AzureMachine as AzureMachine (resource)

    Controller->>HostedCluster: call ValidCredentials(hc)
    alt credentials valid
        Controller-->>Controller: return (no-op)
    else credentials invalid
        Controller->>K8sAPI: List AzureMachine in controlPlaneNamespace
        K8sAPI-->>Controller: list of AzureMachine objects
        loop for each machine
            Controller->>AzureMachine: inspect DeletionTimestamp
            alt DeletionTimestamp set
                Controller->>AzureMachine: clear Finalizers and Update()
                AzureMachine-->>K8sAPI: Update request
                K8sAPI-->>Controller: update result (success/failure)
            else not pending deletion
                Controller-->>AzureMachine: skip
            end
        end
        Controller-->>Controller: aggregate update errors (if any) and return
    end
Loading
🚥 Pre-merge checks | ✅ 11 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All test names in TestValidCredentials and TestDeleteOrphanedMachines are static strings without dynamic values, timestamps, or generated identifiers.
Test Structure And Quality ✅ Passed Tests follow appropriate patterns for standard Go table-driven tests with single responsibility per test and proper isolation using controller-runtime fake client.
Microshift Test Compatibility ✅ Passed The custom check applies specifically to Ginkgo e2e tests. The changes in this PR add only standard Go unit tests using the Go testing package and controller-runtime's fake client, not Ginkgo e2e tests. Since no Ginkgo e2e tests were added, the MicroShift compatibility check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed This PR adds standard Go unit tests, not Ginkgo e2e tests. The check targets Ginkgo e2e patterns like It(), Describe(), Context(), When().
Topology-Aware Scheduling Compatibility ✅ Passed This pull request does not introduce scheduling constraints or topology assumptions. Changes add credential validation and orphaned machine cleanup logic that operates on AzureMachine objects without deployment manifests or scheduling constraints.
Ote Binary Stdout Contract ✅ Passed The PR adds standard library code and unit tests to the Azure platform controller with no process-level stdout writes or OTE binary violations.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed This PR adds standard Go unit tests for Azure platform controller logic, not Ginkgo e2e tests. The test file contains func Test* patterns from the testing package, not Ginkgo-style tests.
Title check ✅ Passed The title accurately describes the main change: orphaning AzureMachine resources when managed identity credentials are invalid during cluster deletion. It clearly summarizes the primary functionality added.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci openshift-ci Bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Apr 21, 2026
@openshift-ci

openshift-ci Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Hi @patilsuraj767. Thanks for your PR.

I'm waiting for a openshift member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci openshift-ci Bot added area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/platform/azure PR/issue for Azure (AzurePlatform) platform labels Apr 21, 2026
@openshift-ci
openshift-ci Bot requested review from csrwng and devguyio April 21, 2026 08:57

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go (1)

652-663: Validation logic will skip assertions when DeletionTimestamp is zero.

The validation condition if !machine.DeletionTimestamp.IsZero() will be false when DeletionTimestamp is &metav1.Time{} (zero value), causing the assertion to never run. Combined with the test setup issue noted above, this results in no actual validation occurring for the pending deletion scenario.

Consider also adding an explicit assertion that at least one machine was checked when expectedFinalizersRemoved is true:

Suggested validation improvement
 			// Validate finalizers were removed if expected
 			if tc.expectedFinalizersRemoved {
 				azureMachineList := &capiazure.AzureMachineList{}
 				err := fakeClient.List(ctx, azureMachineList, client.InNamespace(controlPlaneNamespace))
 				g.Expect(err).ToNot(HaveOccurred())

+				checkedCount := 0
 				for _, machine := range azureMachineList.Items {
 					if !machine.DeletionTimestamp.IsZero() {
+						checkedCount++
 						g.Expect(machine.Finalizers).To(BeEmpty(), "Finalizers should be removed for machines with deletion timestamp")
 					}
 				}
+				g.Expect(checkedCount).To(BeNumerically(">", 0), "Expected at least one machine with deletion timestamp to validate")
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go`
around lines 652 - 663, The validation currently skips assertions when
machine.DeletionTimestamp is the zero metav1.Time value, so update the check in
the expectedFinalizersRemoved block to (1) treat a non-nil, non-zero
DeletionTimestamp as the signal to assert Finalizers were removed (use
machine.DeletionTimestamp != nil && !machine.DeletionTimestamp.IsZero()), (2)
count how many machines you actually checked and add an explicit assertion that
at least one machine was validated when expectedFinalizersRemoved is true (e.g.,
increment a checkedCount while iterating azureMachineList.Items and assert
checkedCount > 0), and (3) keep the existing assertion that machine.Finalizers
is empty for those checked machines; reference azureMachineList,
fakeClient.List, controlPlaneNamespace, machine.DeletionTimestamp, and
machine.Finalizers when making these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go`:
- Around line 583-595: The test uses a zero DeletionTimestamp (&metav1.Time{})
so IsZero() is true and the orphaning logic never runs; update the test's
azureMachines entry (capiazure.AzureMachine with Name "machine-1") to set a
non-zero DeletionTimestamp (e.g., metav1.NewTime(time.Now()) or
&metav1.Time{Time: time.Now()}) and likewise ensure the corresponding machine
used in the validation has a non-zero DeletionTimestamp so the finalizer-removal
branch executes; also add "time" to the imports.

In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go`:
- Around line 412-413: The log message logged via logger.Info for azureMachine
is misleading — it says "skipping cleanup of azuremachine" even though the
controller is removing finalizers/orphaning the machine locally; update the
message to clearly state that cloud-side cleanup is being skipped while the
AzureMachine is being orphaned/left with finalizers removed. Locate the
logger.Info call referencing client.ObjectKeyFromObject(azureMachine) and change
the text to something like "skipping cloud-side cleanup due to invalid Azure
managed identity; orphaning AzureMachine (removed finalizers)" so the action
(orphaning) and scope (cloud-side cleanup skipped) are explicit.

---

Nitpick comments:
In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go`:
- Around line 652-663: The validation currently skips assertions when
machine.DeletionTimestamp is the zero metav1.Time value, so update the check in
the expectedFinalizersRemoved block to (1) treat a non-nil, non-zero
DeletionTimestamp as the signal to assert Finalizers were removed (use
machine.DeletionTimestamp != nil && !machine.DeletionTimestamp.IsZero()), (2)
count how many machines you actually checked and add an explicit assertion that
at least one machine was validated when expectedFinalizersRemoved is true (e.g.,
increment a checkedCount while iterating azureMachineList.Items and assert
checkedCount > 0), and (3) keep the existing assertion that machine.Finalizers
is empty for those checked machines; reference azureMachineList,
fakeClient.List, controlPlaneNamespace, machine.DeletionTimestamp, and
machine.Finalizers when making these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 182f5614-0b1a-40be-9431-17412835330e

📥 Commits

Reviewing files that changed from the base of the PR and between d0a4024 and 92a46ca.

📒 Files selected for processing (2)
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go

Comment thread hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go Outdated
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 21, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go`:
- Around line 387-391: DeleteOrphanedMachines currently runs for all Azure
clusters when ValidCredentials(hc) is false and may orphan machines for
self-managed/workload-identity clusters; restrict this flow to only
managed-identity ARO clusters by adding an early return when the cluster is not
a managed-identity cluster. Concretely, update DeleteOrphanedMachines to call a
cluster-type helper (e.g., IsManagedIdentityCluster(hc) or inline check of
hc.Spec.Platform.Azure fields indicating managed identity) immediately after the
ValidCredentials check and return nil for non-managed-identity clusters; ensure
the helper inspects the HostedCluster Azure platform fields that differentiate
managed-identity vs workload/self-managed identity so the orphaning logic and
ARO cleanup identity path only run for managed-identity clusters.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 95c6feef-6d1a-4ae7-96ee-00e8bdfb0ddd

📥 Commits

Reviewing files that changed from the base of the PR and between 92a46ca and c7bde7f.

📒 Files selected for processing (2)
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go

@machi1990

Copy link
Copy Markdown

@patilsuraj767 This seems to handle the case of missing missing MI when deleting Azure machines. I am thinking that there could be other cases as well that'll fail deletion because of a missing MI (e.g KMS) or because of a missing user brought resources e.g KSM, Vnet, Subnet, or the overall RG etc Are you planning to handle that as well?

@patilsuraj767

Copy link
Copy Markdown
Contributor Author

@patilsuraj767 This seems to handle the case of missing missing MI when deleting Azure machines. I am thinking that there could be other cases as well that'll fail deletion because of a missing MI (e.g KMS) or because of a missing user brought resources e.g KSM, Vnet, Subnet, or the overall RG etc Are you planning to handle that as well?

@machi1990 We need to verify whether the HyperShift delete workflow fails when user-provided resources are missing during deletion. If the cluster deletion fails due to missing user-provided resources, that should be addressed in a separate PR. This change should be scoped only to missing/invalid managed identity handling.

@machi1990

Copy link
Copy Markdown

@patilsuraj767 This seems to handle the case of missing missing MI when deleting Azure machines. I am thinking that there could be other cases as well that'll fail deletion because of a missing MI (e.g KMS) or because of a missing user brought resources e.g KSM, Vnet, Subnet, or the overall RG etc Are you planning to handle that as well?

@machi1990 We need to verify whether the HyperShift delete workflow fails when user-provided resources are missing during deletion. If the cluster deletion fails due to missing user-provided resources, that should be addressed in a separate PR. This change should be scoped only to missing/invalid managed identity handling.

Yes it does and these are the cases we've already seen e.g the recent cspr orphaned are because of these issues.

lastTransitionTime: "2026-04-27T15:24:17Z"
      message: |
        failed to get network security group info to verify its location: failed to get network security group: GET https://management.azure.com/subscriptions/<subId>/resourceGroups/pr-check-e2e-tests-resource-group-b796l/providers/Microsoft.Network/networkSecurityGroups/pr-check-e2e-tests-nsg-fh2x7
        --------------------------------------------------------------------------------
        RESPONSE 404: 404 Not Found
        ERROR CODE: ResourceNotFound
        --------------------------------------------------------------------------------
        {
          "error": {
            "code": "ResourceNotFound",
            "message": "The Resource 'Microsoft.Network/networkSecurityGroups/pr-check-e2e-tests-nsg-fh2x7' under resource group 'pr-check-e2e-tests-resource-group-b796l' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix"
          }
        }
 message: |
        failed to encrypt data using KMS (key: etcd-data-kms-encryption-key/<keyId>): POST https://pr-check-key-vault-p9x9h.vault.azure.net/keys/etcd-data-kms-encryption-key/<keyId>/encrypt
        --------------------------------------------------------------------------------
        RESPONSE 404: 404 Not Found
        ERROR CODE: VaultNotFound
        --------------------------------------------------------------------------------
        {
          "error": {
            "code": "VaultNotFound",
            "message": "Azure Key Vault 'pr-check-key-vault-p9x9h' does not exist."
          }
        }
        --------------------------------------------------------------------------------

@patilsuraj767 okay if it needs to be a separate PR but let's make sure that this is addressed as part of your effort as its not only MI missing that can cause deletion stuck but other infra missing as well can cause deletion to be stuck and its critical we tackle it broadly

@typeid

typeid commented Apr 28, 2026

Copy link
Copy Markdown
Member

/ok-to-test

@openshift-ci openshift-ci Bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Apr 28, 2026
@typeid

typeid commented Apr 29, 2026

Copy link
Copy Markdown
Member

/test e2e-aks e2e-aks-4-22 e2e-aws e2e-aws-4-22 e2e-aws-upgrade-hypershift-operator e2e-azure-self-managed e2e-kubevirt-aws-ovn-reduced e2e-v2-aws

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-azure-self-managed | Build: 2049461271836758016 | Cost: $4.167078350000001 | Failed step: hypershift-azure-run-e2e-self-managed

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@patilsuraj767

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-4-22 e2e-aks-4-22

@patilsuraj767

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-self-managed

@patilsuraj767

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-4-22

for i := range azureMachineList.Items {
azureMachine := &azureMachineList.Items[i]
if !azureMachine.DeletionTimestamp.IsZero() {
// Remove finalizers to orphan the machine

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.

Can't we be specific about which finalizer(s) we intend to remove?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have updated the logic to remove only the specific finalizer instead of removing all finalizers indiscriminately.

}

// If credentials are valid, nothing to do - normal deletion will work
if ValidCredentials(hc) {

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.

Can we race whereby the CPO doesn't have time yet to post the invalid credential status, and we still start the deletion? Can we detect that case and still do the right thing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think it can self-heal, If credentials become invalid around the same time deletion is triggered, ValidCredentials() can return true because CPO didn't completed yet, resulting in AzureMachine provider not able to delete the machine. The machine is stuck in deletion with its DeletionTimestamp set but finalizer never removed.
But HO will keep requeuing because the cluster still exists. Eventually the CPO posts the condition on the HCP, the HO copies it to the HC, and the next call to DeleteOrphanedMachines correctly orphans. So the race is transient.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks-4-22
/test e2e-aws-4-22
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-v2-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws
/test e2e-v2-gke

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-aws | Build: 2074148613692329984 | Cost: $3.4249676499999997 | Failed step: hypershift-aws-run-e2e-nested

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD dda6055 and 2 for PR HEAD 185a7e3 in total

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-aws | Build: 2074187557985325056 | Cost: $2.547166750000001 | Failed step: hypershift-aws-run-e2e-nested

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@patilsuraj767

Copy link
Copy Markdown
Contributor Author

/test e2e-aws

1 similar comment
@patilsuraj767

Copy link
Copy Markdown
Contributor Author

/test e2e-aws

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD a627c48 and 1 for PR HEAD 185a7e3 in total

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD 1aca754 and 0 for PR HEAD 185a7e3 in total

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-aws | Build: 2074634337533300736 | Cost: $2.3044242500000003 | Failed step: hypershift-aws-run-e2e-nested

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/hold

Revision 185a7e3 was retested 3 times: holding

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 8, 2026
@davidffrench

Copy link
Copy Markdown

/test e2e-aws

1 similar comment
@davidffrench

Copy link
Copy Markdown

/test e2e-aws

// deletionFailedThreshold is the minimum duration a machine must have had a non-zero
// DeletionTimestamp before it is considered permanently stuck and eligible for orphaning.
// This guards against orphaning machines that hit transient failures (e.g. rate limiting).
const deletionFailedThreshold = 10 * time.Minute

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.

Do we have a Kusto query showing our distribution of deletion times? If so, please leave it here so someone can re-run the analysis later, and specify what percentile 10 minutes is - p99? p99.99?

@davidffrench

Copy link
Copy Markdown

/test e2e-aws

@hypershift-jira-solve-ci

Copy link
Copy Markdown
Contributor

I now have all the evidence I need. Here is the complete analysis:

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

step [release:initial] failed: failed to get CLI image: unable to find the 'cli' image in the provided release image: 
pod pending for more than 1h0m0s: containers have not started in 1h0m0.000110668s: release:
* Container release is not ready with reason CreateContainerError and message set memory limit 324000 too low; should be at least 524288 bytes

Summary

This is a CI infrastructure failure, completely unrelated to the PR's code changes. The e2e-aws test step never started. The job failed during the [release:initial] step — a pre-test CI pipeline phase that imports the OCP release payload. The CI pod-scaler system set a memory limit of 324k (324,000 bytes) on the release container of pod release-images-initial-cli, but the Linux container runtime (cri-o) requires a minimum cgroup memory limit of 524,288 bytes (512 KB). The container could never start, the pod stayed in Pending/CreateContainerError for the full 1-hour timeout, and the entire job was aborted. A re-trigger of the job should succeed.

Root Cause

The CI infrastructure's pod-scaler component (pod-scaler.openshift.io) set an impossibly low memory limit on the release container in pod release-images-initial-cli. The pod label pod-scaler.openshift.io/measured: "false" confirms the resource values were estimated (not based on actual measurements), and the estimate of 324k was below the Linux kernel's minimum cgroup memory limit of 524288 bytes.

What happened step by step:

  1. ci-operator began importing the release payload registry.ci.openshift.org/ocp/release-5:5.0.0-0.ci-2026-07-08-051042
  2. It created pod release-images-initial-cli in namespace ci-op-13px8wwt on cluster build01
  3. The pod's release container was configured with resources.limits.memory: 324k and resources.requests.memory: 324k — set by the pod-scaler
  4. The init container (ci-scheduling-dns-wait) completed successfully at 08:18:58Z
  5. When the kubelet attempted to create the release container via cri-o, the OCI runtime rejected it: set memory limit 324000 too low; should be at least 524288 bytes
  6. This error repeated 250 times over ~55 minutes (08:19:02 → 09:14:05) as kubelet retried
  7. After 1 hour, ci-operator timed out and reported the job as failed with reason executing_graph:step_failed:importing_release:pod_pending
  8. The actual e2e-aws test step never started — it was blocked waiting for the release import

The PR's changes (orphan machine cleanup for invalid managed identity on Azure clusters) were never compiled into a test binary, never deployed, and never executed. This failure is purely a CI infrastructure issue.

Recommendations
  1. Re-trigger the job — This is a transient CI infrastructure issue. The pod-scaler's estimate was anomalously low and a re-run will likely get a different (valid) memory limit.

  2. If the failure recurs, file a bug against the OpenShift CI pod-scaler component (openshift/ci-tools or DPTP-* in Jira) noting that release-images-initial-cli pods are being assigned sub-minimum memory limits (324k < 512KB minimum).

  3. No code changes needed in the hypershift repository — this failure is entirely in the CI infrastructure layer.

Evidence
Evidence Detail
Failed step [release:initial] — Import the release payload "initial" from an external source
Failing pod release-images-initial-cli in namespace ci-op-13px8wwt
Container release — command: cluster-version-operator image cli > /dev/termination-log
Memory limit set 324k (324,000 bytes) — set by pod-scaler (label pod-scaler.openshift.io/measured: "false")
Minimum required 524,288 bytes (512 KB) — Linux kernel cgroup minimum
Container error CreateContainerError: set memory limit 324000 too low; should be at least 524288 bytes
Error repetitions 250 occurrences between 08:19:02Z and 09:14:05Z
Timeout 1h0m0s — ci-operator aborted after pod stayed Pending for the maximum allowed duration
e2e-aws step Never started (started_at: None) — blocked by release import failure
PR relation None — failure occurred in CI infrastructure before any PR code was tested
Reporting reason executing_graph:step_failed:importing_release:pod_pending
Release image registry.ci.openshift.org/ocp/release-5:5.0.0-0.ci-2026-07-08-051042
CI cluster build01 (console.build01.ci.openshift.org)

@patilsuraj767

Copy link
Copy Markdown
Contributor Author

/test e2e-aws

@bryan-cox

Copy link
Copy Markdown
Member

/hold cancel

@openshift-ci openshift-ci Bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 13, 2026
@redhat-chai-bot

Copy link
Copy Markdown
Contributor

/hold cancel

@bryan-cox

Copy link
Copy Markdown
Member

/ok-to-test

@openshift-ci

openshift-ci Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@patilsuraj767: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot
openshift-merge-bot Bot merged commit 845ed6f into openshift:main Jul 13, 2026
41 checks passed
@openshift-ci-robot

Copy link
Copy Markdown

@patilsuraj767: Jira Issue OCPBUGS-63720: All pull requests linked via external trackers have merged:

This pull request has the verified-later tag and will need to be manually moved to VERIFIED after testing. Jira Issue OCPBUGS-63720 has been moved to the MODIFIED state.

Details

In response to this:

…ter deletion

Summary

When a customer deletes a managed identity required for cleaning up resources in the managed resource group, HyperShift will now skip deletion of those Azure machines and allow the ARO cluster service to handle cleanup using a special Azure 1P application identity.

Fixes: OCPBUGS-63720

Changes

  • Implement DeleteOrphanedMachines for the Azure platform to satisfy the OrphanDeleter interface by inspecting each AzureMachine's own status conditions for Ready=False with Reason=DeletionFailed, rather than relying on HostedCluster-level credential conditions
  • Add a deletionFailedThreshold (10 minutes) based on the machine's DeletionTimestamp to avoid orphaning machines that hit transient cloud API failures
  • Add hasDeletionFailedCondition helper to check individual AzureMachine status conditions
  • Add unit tests covering all relevant scenarios

How it works

  • DeleteOrphanedMachines inspects each AzureMachine individually rather than relying on HostedCluster-level conditions:
  • If ManagedIdentities is nil → return early (not a managed-identity cluster)
  • List all AzureMachine resources in the control plane namespace
  • For each machine, check three conditions before orphaning:
  • The machine has a non-zero DeletionTimestamp (it is being deleted)
  • The DeletionTimestamp is older than 10 minutes (rules out transient failures)
  • The machine has a Ready=False condition with Reason=DeletionFailed (the CAPZ provider explicitly failed to delete the VM, e.g., due to invalid or expired credentials)
  • If all three conditions are met, strip the azuremachine.infrastructure.cluster.x-k8s.io finalizer and log that the machine was orphaned

Testing

Unit tests cover:

  • ManagedIdentities is nil → no orphaning (early return)
  • No machines in namespace → no-op
  • Machine with stale DeletionTimestamp and DeletionFailed condition → finalizer removed
  • Machine with recent DeletionTimestamp and DeletionFailed condition → finalizer not removed (within threshold)
  • Machine with stale DeletionTimestamp but no DeletionFailed condition → finalizer not removed
  • Machine not pending deletion → no modification regardless of conditions

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-merge-robot

Copy link
Copy Markdown
Contributor

Fix included in release 5.0.0-0.nightly-2026-07-14-100335

vsolanki12 added a commit to vsolanki12/hypershift that referenced this pull request Jul 29, 2026
…s during cluster deletion

Replace the credential-level ValidAzureIdentityProvider signal with the
machine-level DeletionFailed condition approach (aligned with PR openshift#8296).

When an AzureMachine has been deleting for >10 minutes and CAPZ sets
Ready=False with Reason=DeletionFailed, the finalizer is removed to
unblock cluster teardown. Unlike openshift#8296 which only covers ARO HCP
(ManagedIdentities != nil), this covers self-managed Azure clusters
where credentials may expire or resource groups may be deleted
out-of-band.

Removes: ValidAzureIdentityProvider condition, CPO health check for
Azure credentials, credential status types, and condition bubbling
from HCP to HC.

Keeps: cmd/cluster/azure/destroy.go 404 handling fix.

Signed-off-by: Vimal Solanki <vsolanki@redhat.com>
vsolanki12 added a commit to vsolanki12/hypershift that referenced this pull request Jul 29, 2026
…s during cluster deletion

Replace the credential-level ValidAzureIdentityProvider signal with the
machine-level DeletionFailed condition approach (aligned with PR openshift#8296).

When an AzureMachine has been deleting for >10 minutes and CAPZ sets
Ready=False with Reason=DeletionFailed, the finalizer is removed to
unblock cluster teardown. Unlike openshift#8296 which only covers ARO HCP
(ManagedIdentities != nil), this covers self-managed Azure clusters
where credentials may expire or resource groups may be deleted
out-of-band.

Removes: ValidAzureIdentityProvider condition, CPO health check for
Azure credentials, credential status types, and condition bubbling
from HCP to HC.

Keeps: cmd/cluster/azure/destroy.go 404 handling fix.

Signed-off-by: Vimal Solanki <vsolanki@redhat.com>
vsolanki12 added a commit to vsolanki12/hypershift that referenced this pull request Jul 29, 2026
…s during cluster deletion

Replace the credential-level ValidAzureIdentityProvider signal with the
machine-level DeletionFailed condition approach (aligned with PR openshift#8296).

When an AzureMachine has been deleting for >10 minutes and CAPZ sets
Ready=False with Reason=DeletionFailed, the finalizer is removed to
unblock cluster teardown. Unlike openshift#8296 which only covers ARO HCP
(ManagedIdentities != nil), this covers self-managed Azure clusters
where credentials may expire or resource groups may be deleted
out-of-band.

Removes: ValidAzureIdentityProvider condition, CPO health check for
Azure credentials, credential status types, and condition bubbling
from HCP to HC.

Keeps: cmd/cluster/azure/destroy.go 404 handling fix.

Signed-off-by: Vimal Solanki <vsolanki@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/platform/azure PR/issue for Azure (AzurePlatform) platform jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. verified Signifies that the PR passed pre-merge verification criteria verified-later

Projects

None yet

Development

Successfully merging this pull request may close these issues.