Skip to content

Conversation

@JGAntunes
Copy link
Member

@JGAntunes JGAntunes commented Oct 29, 2025

What this PR does / why we need it:

Adds verifications that the upgrade is possible.

Which issue(s) this PR fixes:

https://app.shortcut.com/replicated/story/130790/add-verification-that-release-is-deployable

Does this PR require a test?

Yes, added unit tests, we don't have a dryrun test for upgrades yet, I would imagine this would be one test we could add. Unsure if we should make it part of this PR or not.

There's still some manual tests I want to run though.

Does this PR require a release note?

NONE

Does this PR require documentation?

NONE

@JGAntunes JGAntunes changed the title Jgantunes/sc 130790/add verification that release is deployable feat(upgrade): add verification release is deployable Oct 29, 2025
@JGAntunes JGAntunes self-assigned this Oct 30, 2025
@github-actions
Copy link

github-actions bot commented Oct 30, 2025

This PR has been released (on staging) and is available for download with a embedded-cluster-smoke-test-staging-app license ID.

Online Installer:

curl "https://staging.replicated.app/embedded/embedded-cluster-smoke-test-staging-app/ci/appver-dev-473d223" -H "Authorization: $EC_SMOKE_TEST_LICENSE_ID" -o embedded-cluster-smoke-test-staging-app-ci.tgz

Airgap Installer (may take a few minutes before the airgap bundle is built):

curl "https://staging.replicated.app/embedded/embedded-cluster-smoke-test-staging-app/ci-airgap/appver-dev-473d223?airgap=true" -H "Authorization: $EC_SMOKE_TEST_LICENSE_ID" -o embedded-cluster-smoke-test-staging-app-ci.tgz

Happy debugging!

@JGAntunes JGAntunes force-pushed the jgantunes/sc-130790/add-verification-that-release-is-deployable branch from 5e75ed0 to e21fcad Compare October 30, 2025 13:26
if len(requiredReleases) > 0 {
// Extract version labels from required releases
for _, release := range requiredReleases {
requiredVersions = append(requiredVersions, release.VersionLabel)
Copy link
Member

Choose a reason for hiding this comment

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

why dont you check TargetAppSequence here like you do for online?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is wrong yes, I'm trying to figure out how the required versions are sorted and what gets added to the metadata.

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed it in the latest changes.

}

// Check if minor version is being skipped
if targetK8s.Minor() > currentK8s.Minor()+1 {
Copy link
Member

Choose a reason for hiding this comment

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

do you also need to check for downgrade here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not doing it because we're also checking for EC version downgrades already (and block it altogether) so that code path would never be used. We could do it if we want to ensure correctness though.

}

// GetPendingReleases fetches pending releases from the Replicated API
func (c *client) GetPendingReleases(ctx context.Context, channelID string, currentSequence int64, opts *PendingReleasesOptions) (*PendingReleasesResponse, error) {
Copy link
Member

Choose a reason for hiding this comment

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

is it worth adding reporting info to this call? i know we can add the app status, sequence, number of nodes, etc...

it could be done in a follow up

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question... Idk 🤷 who would be the best person to talk about this reporting info, its use and what's expected?

We have other instances in the cli where we hit this endpoint without sending any data whatsoever -

func getCurrentAppChannelRelease(ctx context.Context, license *kotsv1beta1.License, channelID string) (*apiChannelRelease, error) {
query := url.Values{}
query.Set("selectedChannelId", channelID)
query.Set("channelSequence", "") // sending an empty string will return the latest channel release
query.Set("isSemverSupported", "true")
apiURL := replicatedAppURL()
url := fmt.Sprintf("%s/release/%s/pending?%s", apiURL, license.Spec.AppSlug, query.Encode())

}
upgradeConfig.license = updatedLicense
upgradeConfig.licenseBytes = licenseBytes
upgradeConfig.replicatedAPIClient = replicatedAPI
Copy link
Member

Choose a reason for hiding this comment

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

this should be taken out of the conditional as it is only set in airgap mode

Copy link
Member Author

Choose a reason for hiding this comment

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

It's the other way around, it's only set in online mode right? And isn't that what we want? In airgap there's no point in initialising the replicated API client right?

@JGAntunes JGAntunes force-pushed the jgantunes/sc-130790/add-verification-that-release-is-deployable branch from 0f083d4 to 2fabba8 Compare November 4, 2025 11:40
@JGAntunes JGAntunes marked this pull request as ready for review November 4, 2025 18:17
@JGAntunes JGAntunes requested a review from emosbaugh November 4, 2025 18:18
cursor[bot]

This comment was marked as outdated.

}

// Perform validation
if err := validation.ValidateIsReleaseUpgradable(ctx, opts); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

the logic that builds these opts should also be put into its own "hop" (sub-function) and unit tested IMO because there's an external dependency at the end of this path. note: the installation object should be passed to it though so it doesn't interact with the cluster or need a fake k8s client.

Copy link
Member Author

Choose a reason for hiding this comment

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

@sgalsaleh, we cannot unit test this method, it has a replicated API dependency. Internally we've added a function that we unit test:

  • } else {
    if err := opts.WithOnlineRequiredReleases(ctx, upgradeConfig.replicatedAPIClient); err != nil {
    return fmt.Errorf("failed to extract required releases from replidated API's pending release call: %w", err)
    }

This method is unit tested:

So I'm trying to understand what we need to unit test, is it this logic?

  • // Get current and target EC/K8s versions
    var currentECVersion string
    if currentInstallation.Spec.Config != nil {
    currentECVersion = currentInstallation.Spec.Config.Version
    }
    targetECVersion := versions.Version
    // Build validation options
    opts := validation.UpgradableOptions{
    CurrentECVersion: currentECVersion,
    TargetECVersion: targetECVersion,
    License: upgradeConfig.license,
    }
    // Add current app version info if available
    if upgradeConfig.currentAppVersion != nil {
    opts.CurrentAppVersion = upgradeConfig.currentAppVersion.VersionLabel
    opts.CurrentAppSequence = upgradeConfig.currentAppVersion.ChannelSequence
    }
    // Add target app version info
    opts.TargetAppVersion = channelRelease.VersionLabel
    opts.TargetAppSequence = channelRelease.ChannelSequence

Copy link
Member Author

Choose a reason for hiding this comment

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

Or we only add a test for airgap?

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.

4 participants