Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
36fcdf0
Add rancherupgrade package: Longhorn pre/post/chart-upgrade validation
floatingman Oct 8, 2026
f563865
Add validation/Jenkinsfile.rancher-upgrade.e2e six-stage upgrade orch…
floatingman Oct 8, 2026
3e14ff9
Add awsNodeTemplate to upgrade cattle-config for SG authorization
floatingman Oct 8, 2026
90381bd
Make repo/executor params sticky against declarative parameter sync
floatingman Oct 8, 2026
263293c
Wait up to ten minutes for the checksum PVC to bind
floatingman Oct 8, 2026
bd78700
Collect failure diagnostics before destroy and image cleanup
floatingman Oct 8, 2026
c1237a5
Smoke-check the rotated token and the dispatched config post-upgrade
floatingman Oct 8, 2026
a5420c2
Accept the insecure LB cert in the rotated-token smoke check
floatingman Oct 8, 2026
ae95642
Export the token before yq injection (empty-adminToken 401 root cause)
floatingman Oct 8, 2026
739d5ac
Address PR review: phase progress logs, build-pinned image tags
floatingman Oct 8, 2026
b14003d
fix: decide teardown in post.always, defer artifact removal to cleanup
floatingman Oct 19, 2026
84bac3d
Address PR review: pit.weekly build tag, skip suite outside the upgra…
floatingman Oct 20, 2026
0848729
Address PR review: fail on pipeline misconfig via rancherUpgradePipel…
floatingman Oct 20, 2026
da60028
Address PR 986 review findings: checksum validation, stale catalog gu…
floatingman Oct 21, 2026
a19485d
Address hamistao review findings: dedupe deployment helper, clarify v…
floatingman Oct 21, 2026
96940e5
Generalize rancher-upgrade pipeline to a TEST_MODULE selector (#968)
floatingman Oct 22, 2026
4eb7358
Thread the node SSH key through the test config for the fleet module
floatingman Oct 22, 2026
7d4b284
Thread the StackState connection settings for the observability module
floatingman Oct 23, 2026
579878d
Guard the StackState license credential before deploy
floatingman Oct 23, 2026
223ce7a
Run every rancherupgrade module in one pipeline (TEST_MODULE=all)
floatingman Oct 27, 2026
c67f600
Sequence the all-mode chart phase observability-first
floatingman Oct 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions actions/charts/longhorn.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"

catalogv1 "github.com/rancher/rancher/pkg/apis/catalog.cattle.io/v1"
"github.com/rancher/shepherd/clients/rancher"
"github.com/rancher/shepherd/clients/rancher/catalog"
shepherdCharts "github.com/rancher/shepherd/extensions/charts"
Expand Down Expand Up @@ -100,6 +101,123 @@ func InstallLonghornChart(client *rancher.Client, payload PayloadOpts, values ma
return err
}

// UpgradeLonghornChart upgrades the longhorn and longhorn-crd charts to
// installOptions.Version on installOptions.Cluster and waits for Deployed state.
// No session cleanup is registered: the uninstall cleanup belongs to the install
// call of the same session, and upgrade-test sessions must not delete the chart.
func UpgradeLonghornChart(client *rancher.Client, installOptions *InstallOptions) error {
serverSetting, err := client.Management.Setting.ByID(serverURLSettingID)
if err != nil {
return err
}

registrySetting, err := client.Management.Setting.ByID(defaultRegistrySettingID)
if err != nil {
return err
}

longhornChartUpgradeActionPayload := &PayloadOpts{
InstallOptions: *installOptions,
Name: LonghornChartName,
Namespace: LonghornNamespace,
Host: serverSetting.Value,
DefaultRegistry: registrySetting.Value,
}

chartUpgradeAction := newLonghornChartUpgradeAction(longhornChartUpgradeActionPayload)

catalogClient, err := client.GetClusterCatalogClient(installOptions.Cluster.ID)
if err != nil {
return err
}

bodyBytes, err := json.Marshal(chartUpgradeAction)
if err != nil {
return err
}
err = ChartActionWithRetry(context.TODO(), client, verbUpgrade, longhornChartUpgradeActionPayload, catalog.RancherChartRepo, []string{LonghornChartName, LonghornChartName + "-crd"}, buildRepoActionRequest(catalogClient, catalog.RancherChartRepo, verbUpgrade, bodyBytes))
if err != nil {
return err
}

adminClient, err := rancher.NewClient(client.RancherConfig.AdminToken, client.Session)
if err != nil {
return err
}

adminCatalogClient, err := adminClient.GetClusterCatalogClient(installOptions.Cluster.ID)
if err != nil {
return err
}

watchAppInterface, err := adminCatalogClient.Apps(LonghornNamespace).Watch(context.TODO(), metav1.ListOptions{
FieldSelector: "metadata.name=" + LonghornChartName,
TimeoutSeconds: &defaults.WatchTimeoutSeconds,
})
if err != nil {
return err
}

err = wait.WatchWait(watchAppInterface, func(event watch.Event) (ready bool, err error) {
app := event.Object.(*catalogv1.App)

state := app.Status.Summary.State
if state == string(catalogv1.StatusPendingUpgrade) {
return true, nil
}

return false, nil
})
if err != nil {
return err
}

watchAppInterface, err = adminCatalogClient.Apps(LonghornNamespace).Watch(context.TODO(), metav1.ListOptions{
FieldSelector: "metadata.name=" + LonghornChartName,
TimeoutSeconds: &defaults.WatchTimeoutSeconds,
})
if err != nil {
return err
}

err = wait.WatchWait(watchAppInterface, func(event watch.Event) (ready bool, err error) {
app := event.Object.(*catalogv1.App)

state := app.Status.Summary.State
if state == string(catalogv1.StatusDeployed) {
return true, nil
}

return false, nil
})
if err != nil {
return err
}

err = shepherdCharts.WatchAndWaitDeployments(client, installOptions.Cluster.ID, LonghornNamespace, metav1.ListOptions{})
if err != nil {
return err
}

return shepherdCharts.WatchAndWaitDaemonSets(client, installOptions.Cluster.ID, LonghornNamespace, metav1.ListOptions{})
}

// newLonghornChartUpgradeAction is a private helper function that returns the chart upgrade action for Longhorn.
func newLonghornChartUpgradeAction(p *PayloadOpts) *types.ChartUpgradeAction {
// Pass the deletingConfirmationFlag value on the main chart so the upgrade does
// not reset it; the CRD chart takes no Longhorn settings (same split as install).
chartUpgrade := NewChartUpgrade(p.Name, p.Name, p.Version, p.Cluster.ID, p.Cluster.Name, p.Host, p.DefaultRegistry, enableDeletionSetting)
chartUpgradeCRD := NewChartUpgrade(p.Name+"-crd", p.Name+"-crd", p.Version, p.Cluster.ID, p.Cluster.Name, p.Host, p.DefaultRegistry, nil)
chartUpgrades := []types.ChartUpgrade{*chartUpgradeCRD, *chartUpgrade}

chartUpgradeAction := NewChartUpgradeAction(p.Namespace, chartUpgrades)
// Disable OpenAPI validation to avoid schema-conflict failures on the large
// Longhorn CRDs, which frequently change shape between versions.
chartUpgradeAction.DisableOpenAPIValidation = true

return chartUpgradeAction
}

// UninstallLonghornChart removes Longhorn from the cluster related to the received catalog client object.
func UninstallLonghornChart(client *rancher.Client, namespace string, clusterID string, rancherHostname string) error {
catalogClient, err := client.GetClusterCatalogClient(clusterID)
Expand Down
40 changes: 40 additions & 0 deletions actions/clusters/local.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package clusters

import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"time"

"github.com/Masterminds/semver/v3"
"github.com/rancher/shepherd/clients/rancher"
"github.com/rancher/shepherd/extensions/defaults"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/wait"
)

const (
Expand Down Expand Up @@ -37,6 +42,41 @@ func IsRancherVersionAbove(client *rancher.Client, minVersion string) (bool, err
return serverVersion.GreaterThan(minimumVersion), nil
}

// WaitRancherVersion polls the management server-version setting until it equals
// targetVersion (semver-compared) or timeout elapses. Gates post-upgrade assertions
// on Rancher server convergence; transient read errors during the upgrade rollout
// are retried, not returned.
func WaitRancherVersion(client *rancher.Client, targetVersion string, timeout time.Duration) error {
target, err := parseRancherVersion(targetVersion)
if err != nil {
return err
}

return wait.PollUntilContextTimeout(context.Background(), defaults.TenSecondTimeout, timeout, true, func(ctx context.Context) (done bool, err error) {
serverVersionRawValue, err := client.Management.Setting.ByID(serverVersionSetting)
if err != nil {
// The server may be mid-restart during the upgrade rollout; retry the read.
// Logged so a terminal cause (e.g. a revoked token or unreachable API)
// is visible in the log instead of surfacing only as the final timeout.
logrus.Debugf("server-version read failed, retrying: %v", err)
return false, nil
}

serverVersion, err := parseRancherVersion(serverVersionRawValue.Value)
if err != nil {
logrus.Debugf("server-version value %q not parseable yet, retrying: %v", serverVersionRawValue.Value, err)
return false, nil
}

if serverVersion.Equal(target) {
return true, nil
}

logrus.Debugf("Rancher server version is %q, waiting for %q", serverVersionRawValue.Value, targetVersion)
return false, nil
})
}

func parseRancherVersion(versionInput string) (*semver.Version, error) {
trimmedVersion := strings.TrimSpace(strings.TrimPrefix(versionInput, "v"))
if trimmedVersion == "" {
Expand Down
Loading
Loading