Skip to content

Remove Cincinnati upgrade-graph validation for nodepool upgrades - #5153

Merged
openshift-merge-bot[bot] merged 6 commits into
mainfrom
asampaio/ARO-26792
May 21, 2026
Merged

openshift-merge-bot[bot] merged 6 commits into
mainfrom
asampaio/ARO-26792

Conversation

@adalrsjr1

@adalrsjr1 Adalberto Sampaio (adalrsjr1) commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Fixes: ARO-26792

(updated)

What

Replace Cincinnati upgrade-edge validation with a version existence check in the nodepool version controller. The backend now verifies the desired version exists in
Cincinnati but no longer requires an upgrade edge from the current version. Static Kubernetes version skew constraints remain enforced (nodepool ≤ CP version, no downgrade,
within minor+1).

Per David Eads (@deads2k) suggestion, this work is split into two PRs:

  1. (this PR) Remove edge requirement, keep version existence check
  2. Remove downgrade restriction for nodepool versions (Allow nodepool version downgrades for HCP clusters #5184)

Why

HCP nodepools use the Replace upgrade strategy — nodes are destroyed and recreated at the target version, not upgraded in-place. Cincinnati upgrade edges are irrelevant for
this strategy.

The controller was querying Cincinnati for every nodepool upgrade and requiring an edge from the current to the desired version. When no edge existed (e.g. 4.20.8 →
4.21.1), it entered a permanent error-retry loop. ARM reported Succeeded while the upgrade never progressed, leaving customers with no visibility into the failure.

Testing

  • Unit tests: Replaced edge-check mocks with existence-check mocks. Added SucceedsWithoutCincinnatiEdge (version exists but no edge → succeeds) and
    VersionNotInCincinnatiFails (version doesn't exist → fails). Updated DesiredVersionUnchangedOnFailure to test VersionNotFound instead of missing edges.
  • E2E: Existing y-stream upgrade test (4.20.z → 4.21.zLatest) validates the fix end-to-end. Verified locally against a dev cluster — nodepool upgraded from 4.20.20 to
    4.21.14 successfully.

Special notes for your reviewer

Depends on CS MR !322 — CS also validates upgrade edges via AvailableUpgrades
in ValidateNodePoolUpgradeVersion(). Without the CS change, the backend accepts the version but CS blocks the upgrade policy. Safe to deploy in any order — neither change
alone creates a regression.

A rationale comment in validateDesiredNodePoolVersion notes that if an InPlace upgrade strategy is introduced in the future, strategy-specific upgrade validation should
be added.

Copilot AI 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.

Pull request overview

Removes Cincinnati upgrade-graph validation from the backend nodepool version controller so nodepool upgrades are validated only via static Kubernetes/OpenShift version skew constraints (no downgrades, nodepool ≤ control plane, no minor skipping), aligning with the HCP nodepool Replace upgrade strategy.

Changes:

  • Removed Cincinnati client initialization/caching and upgrade-edge checks from nodepool_version_controller.
  • Updated unit tests to drop Cincinnati mocks and assert static validation behavior instead.
  • Adjusted the nodepool version upgrade E2E test wording/comments to reflect that backend validation no longer depends on Cincinnati edges (while still using Cincinnati for test version discovery).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
test/e2e/nodepool_version_upgrade.go Updates test comments/log messages around version selection for nodepool upgrades.
backend/pkg/controllers/upgradecontrollers/nodepool_version_controller.go Removes Cincinnati upgrade-edge validation and related client/cache code; keeps static version-skew validation.
backend/pkg/controllers/upgradecontrollers/nodepool_version_controller_test.go Removes Cincinnati mocking and updates/rewrites tests to validate new static-only behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/e2e/nodepool_version_upgrade.go Outdated
Comment on lines 795 to 799
syncer := &nodePoolVersionSyncer{
cooldownChecker: &alwaysSyncCooldownChecker{},
clusterManagementClusterContentLister: newValidHostedClusterContentLister(t),
cosmosClient: mockDB,
clusterServiceClient: mockCS,
clusterToCincinnatiClient: lru.New(100),
cooldownChecker: &alwaysSyncCooldownChecker{},
cosmosClient: mockDB,
clusterServiceClient: mockCS,
}
Comment on lines 879 to 883
// --- Phase 2: Change version to a downgrade, should fail, desired should NOT change ---

// Update the HCPNodePool with a new desired version
// Update the HCPNodePool with a version that is a downgrade from the active version (4.19.10)
nodePool, err := mockDB.HCPClusters(testSubscriptionID, testResourceGroupName).
NodePools(testClusterName).Get(ctx, testNodePoolName)

@swiencki Simon Wiencki (swiencki) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Three comments inline. Substance-only review across rubber-duck + GPT-5.5 + Opus 4.7 1M; the headline finding is the test-coverage gap vs ARO-26792 AC #2.

Comment thread test/e2e/nodepool_version_upgrade.go

// Validate the customer's desired version before setting it
if err := c.validateDesiredNodePoolVersion(ctx, &customerDesiredVersion, existingServiceProviderNodePool, existingServiceProviderCluster, subscription, nodePool.Properties.Version.ChannelGroup, clusterKey, clusterUUID); err != nil {
if err := c.validateDesiredNodePoolVersion(ctx, &customerDesiredVersion, existingServiceProviderNodePool, existingServiceProviderCluster, subscription); err != nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Cincinnati was also implicitly checking the version exists in the channel. After this PR a non-existent version like 4.20.999 passes the static gate. Is CS the authoritative availability check now? Worth being explicit so we don't regress into the same "ARM Succeeded, never progresses" shape for a different reason.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CS checks that the version exists but we so also check it in here. Otherwise we will have the same issue, as this validation will pass for a well formed but not existed version (4.20.999) but fail "silently" to the user in CS.

So, we need to make a call here to Cincinnati to check that the version exists.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not sure what we do for deployment/install but why not just use the same validation as we do there? Is that different from this flow? I would expect that this would prevent both of those situations

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We don't have this for install. The creation of the nodepool is not yet done in the backend, and adding the cincinnati call to the frontend will increase our time response. Let's add it here, and once we have the node pool creation call in the backend we can add the same validation there.

Comment thread backend/pkg/controllers/upgradecontrollers/nodepool_version_controller.go Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. I personally still on the fence about this change and I'd have kept the validation and give customer two options:
  • Either they recreate their node pool if they don't care about "validated" upgradeability
  • Or they do hops from v1, v2...vDesired

I understand that these might not always be better UX but I personally feel like they are better options that doesn't bypass upgrades gates.
If this use case gets an approval from BU & David Eads (@deads2k) I won't stand on the way of it. Please let's get that approval from them. Also I am looping in Alba Hita (@ahitacat) for review as well.

  1. CS component is also involved in the upgrade and has the upgradeability check; can you double check if there is anything that needs to be done on the CS component as well?

@ahitacat Alba Hita (ahitacat) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In addition to Manyanda Chitimbo (@machi1990) review #5153 (review)

In CS when creating the upgrade policy we also check that the version has an upgradepath. That should be change before this, so otherwise we could have the same issue, as the controller that creates these policies (trigger_nodepool_upgrade_controller) will fail.


// Validate the customer's desired version before setting it
if err := c.validateDesiredNodePoolVersion(ctx, &customerDesiredVersion, existingServiceProviderNodePool, existingServiceProviderCluster, subscription, nodePool.Properties.Version.ChannelGroup, clusterKey, clusterUUID); err != nil {
if err := c.validateDesiredNodePoolVersion(ctx, &customerDesiredVersion, existingServiceProviderNodePool, existingServiceProviderCluster, subscription); err != nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CS checks that the version exists but we so also check it in here. Otherwise we will have the same issue, as this validation will pass for a well formed but not existed version (4.20.999) but fail "silently" to the user in CS.

So, we need to make a call here to Cincinnati to check that the version exists.

Comment thread backend/pkg/controllers/upgradecontrollers/nodepool_version_controller.go Outdated
@adalrsjr1

Adalberto Sampaio (adalrsjr1) commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

per David Eads (@deads2k) suggestion this change was split into two parts (part 2 in #5184)

  1. pr/1 (this one) remove the requirement for an edge, but keep the requirement for "version exists in cincinnati"
  2. pr/2 (Allow nodepool version downgrades for HCP clusters #5184) remove the restriction about moving nodepool versions backwards and update testing to include one example of doing this (no need to check this for every version)

The previous comments were addressed in this PR. Both PRs are pending on the update on CS (MR 322) FYI Manyanda Chitimbo (@machi1990) Alba Hita (@ahitacat)

@swiencki Simon Wiencki (swiencki) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed, code looks good, no blockers from my side. Concerns in #5153 (review) should be addressed. Reviewed the CS MR too (https://gitlab.cee.redhat.com/service/aro-hcp-clusters-service/-/merge_requests/322) with one non-blocking note.

@deads2k

Copy link
Copy Markdown
Collaborator

/approve

I'll leave lgtm to another reviewer.

@ahitacat Alba Hita (ahitacat) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

After this is merged we can remove the check of the upgrade path. I.e. so we don't skip this.
https://github.com/Azure/ARO-HCP/blob/main/test/e2e/nodepool_version_upgrade.go#L184

Also, I think is worth it to test this with an e2e. Right now from 4.20.8 -> 4.20.9 there is no upgrade path. We could have an e2e that checks in cincinnati a case like this and upgrades succesfully. Can you add it (it should be skipped before this gets merge but we can test it)

@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

After this is merged we can remove the check of the upgrade path. I.e. so we don't skip this. https://github.com/Azure/ARO-HCP/blob/main/test/e2e/nodepool_version_upgrade.go#L184

Also, I think is worth it to test this with an e2e. Right now from 4.20.8 -> 4.20.9 there is no upgrade path. We could have an e2e that checks in cincinnati a case like this and upgrades succesfully. Can you add it (it should be skipped before this gets merge but we can test it)

Alba Hita (@ahitacat)

I also addressed your comments on CS 322; pending on your approval.

@openshift-ci openshift-ci Bot removed the lgtm label May 19, 2026
@adalrsjr1

Adalberto Sampaio (adalrsjr1) commented May 20, 2026

Copy link
Copy Markdown
Collaborator Author

/retest

53 minutes waiting for a free identity container

@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

/retest

@geoberle

Copy link
Copy Markdown
Collaborator

/lgtm

@openshift-ci openshift-ci Bot added the lgtm label May 20, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD 4cf9d9c and 2 for PR HEAD 6224f84 in total

@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

/retest

@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

/retest due to container identity exhaustion (tests passed, clean ups failed)

@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

/retest

2 similar comments
@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

/retest

@adalrsjr1

Copy link
Copy Markdown
Collaborator Author

/retest

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD 2d20aac and 1 for PR HEAD 6224f84 in total

… check for nodepool upgrades

HCP nodepools use the Replace upgrade strategy — nodes are destroyed and
recreated at the target version, not upgraded in-place. Cincinnati upgrade
edges are irrelevant; only version existence and Kubernetes version skew
constraints apply.

Per @deads2k suggestion, this work is split into two PRs:
  1/2: Remove edge requirement, keep version existence check (this PR)
  2/2: Remove downgrade restriction for nodepool versions

Replaces validateUpgradePathAvailable (which required a Cincinnati edge
from current to desired version) with validateVersionExistsInCincinnati
(which only verifies the desired version exists in the Cincinnati graph).
Static validation remains: no downgrade, ≤ CP version, within minor+1.

Depends on CS MR !322:
https://gitlab.cee.redhat.com/service/aro-hcp-clusters-service/-/merge_requests/322

Fixes: ARO-26792

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add GetVersionPairWithoutUpgradeEdge helper to find version pairs
  without Cincinnati upgrade edges for E2E testing
- Add pending E2E test for forward upgrade without Cincinnati edge,
  exercising the actual bug scenario (e.g. 4.20.8 -> 4.20.9)
- Rename UpgradePathExistsSucceeds to ValidUpgradeSucceeds to reflect
  that the test validates static version checks, not edge existence

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add HyperShift Replace strategy docs link
- Rename ErrNoNoEdgePairFound to ErrNoEdgePairFound (duplicated "No")
- Build Cincinnati channel from parsed major.minor to handle X.Y.Z input
- Return clearer error when fewer than 2 parseable versions in minor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment on lines +311 to +319
channel := fmt.Sprintf("%s-%d.%d", channelGroup, requestedMinor.Major, requestedMinor.Minor)
graphURL := fmt.Sprintf("https://api.openshift.com/api/upgrades_info/v1/graph?channel=%s", url.QueryEscape(channel))

req, err := http.NewRequestWithContext(ctx, http.MethodGet, graphURL, nil)
if err != nil {
return semver.Version{}, semver.Version{}, fmt.Errorf("create graph request for %s: %w", channel, err)
}

client := &http.Client{Timeout: graphAPIRequestTimeout}
Comment on lines +249 to +252
DescribeTable("should upgrade a nodepool to a version without Cincinnati upgrade edge",
func(ctx context.Context, minor string) {
Skip("skipped until PR #5184 is merged and deployed")

@geoberle

Copy link
Copy Markdown
Collaborator

/lgtm

@openshift-ci openshift-ci Bot added the lgtm label May 21, 2026
@openshift-ci

openshift-ci Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: adalrsjr1, deads2k, geoberle

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot
openshift-merge-bot Bot merged commit 7ff36d2 into main May 21, 2026
16 checks passed
@openshift-merge-bot
openshift-merge-bot Bot deleted the asampaio/ARO-26792 branch May 21, 2026 20:51
Adalberto Sampaio (adalrsjr1) added a commit that referenced this pull request May 26, 2026
…st coverage

Absorb main (PRs #5153, #5239), then apply downgrade-specific changes:
- Remove downgrade guard from admission webhook
- Rename ValidateNodePoolUpgrade → ValidateNodePoolVersionChange
- Add downgrade E2E tests (z-stream, y-stream at N-2 boundary)
- Add multi-element activeVersions unit tests
- Add cross-major downgrade path tests (4.21, 4.23, 5.1, 5.2)
- Align doc comments across validators, admission, and controller

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants