Skip to content

Commit

Permalink
Upgrade path detection will now only prevent downgrades (#653)
Browse files Browse the repository at this point in the history
This operator update removes logic that prevented upgrades if the user
skipped too many releases. This change is consistent with a recent
update to the Vertica documentation, which no longer requires users to
upgrade through all intermediate releases.

The old documentation stated that "Vertica upgrades must be performed in
a linear fashion, with each release upgraded before the next." However,
this requirement has been removed. Users can now upgrade to any
supported release, regardless of whether they have skipped intermediate
releases.

The only restriction that the operator still enforces is that users
cannot downgrade.
  • Loading branch information
spilchen authored Jan 5, 2024
1 parent c33e209 commit a97d95f
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 96 deletions.
5 changes: 5 additions & 0 deletions changes/unreleased/Changed-20240104-142619.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: Changed
body: Upgrade path detection now only blocks downgrades.
time: 2024-01-04T14:26:19.176420747-04:00
custom:
Issue: "653"
3 changes: 1 addition & 2 deletions pkg/meta/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ const (

// When set to False, this parameter will ensure that when changing the
// vertica version that we follow the upgrade path. The Vertica upgrade
// path means you cannot downgrade a Vertica release, nor can you skip any
// released Vertica versions when upgrading.
// path means you cannot downgrade a Vertica release.
IgnoreUpgradePathAnnotation = "vertica.com/ignore-upgrade-path"
IgnoreUpgradePathAnntationTrue = "true"
IgnoreUpgradePathAnntationFalse = "false"
Expand Down
79 changes: 2 additions & 77 deletions pkg/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,44 +30,12 @@ type Info struct {
Components // The same version as VdbVer but broken down into individual components
}

const (
LTSMinor = 4
LTSPatch = 0
)

// UpgradePaths has all of the vertica releases supported by the operator. For
// each release, the next release that must be upgrade too. Use this map to
// know if a new version is the next supported version by Vertica.
//
// As a general rule of thumb, this map needs to be updated each time a new
// Vertica version introduces a new major or minor version (e.g. 11.1.x ->
// 12.0.x). You don't need to update it for patch releases because we only
// enforce the upgrade path for major/minor versions.
var UpgradePaths = map[Components]Info{
{11, 0, 0}: {"v11.1.x", Components{11, 1, 0}},
{11, 0, 1}: {"v11.1.x", Components{11, 1, 0}},
{11, 0, 2}: {"v11.1.x", Components{11, 1, 0}},
{11, 1, 0}: {"v12.0.x", Components{12, 0, 0}},
{11, 1, 1}: {"v12.0.x", Components{12, 0, 0}},
{12, 0, 0}: {"v23.3.x", Components{23, 4, 0}},
{12, 0, 1}: {"v23.3.x", Components{23, 4, 0}},
{12, 0, 2}: {"v23.3.x", Components{23, 4, 0}},
{12, 0, 3}: {"v23.3.x", Components{23, 4, 0}},
{12, 0, 4}: {"v23.3.x", Components{23, 4, 0}},
}

// MakeInfoFromStr will construct an Info struct by parsing the version string
func MakeInfoFromStr(curVer string) (*Info, bool) {
ma, mi, pa, ok := parseVersion(curVer)
return &Info{curVer, Components{ma, mi, pa}}, ok
}

// buildVersionStr will build the version string from
// a Components object
func (c *Components) buildVersionStr() string {
return fmt.Sprintf("v%d.%d.%d", c.VdbMajor, c.VdbMinor, c.VdbPatch)
}

// IsEqualOrNewer returns true if the version in the Vdb is is equal or newer
// than the given version
func (i *Info) IsEqualOrNewer(inVer string) bool {
Expand Down Expand Up @@ -132,28 +100,6 @@ func (i *Info) IsOlderOrEqualExceptPatch(other *Info) bool {
return i.IsEqualExceptPatch(other) || i.IsOlderExceptPatch(other)
}

// isLTSRelease returns true if the release is LTS
// meaning its version has the format x.4.x
func (i *Info) isLTSRelease() bool {
return i.VdbMinor == LTSMinor
}

// getNextLTSVersion given a release returns the next
// LTS realease version
func (i *Info) getNextLTSVersion() Info {
nextLTSVersion := Info{
VdbVer: i.VdbVer,
}
nextLTSVersion.VdbMajor = i.VdbMajor
nextLTSVersion.VdbMinor = LTSMinor
nextLTSVersion.VdbPatch = LTSPatch
if i.isLTSRelease() {
nextLTSVersion.VdbMajor++
nextLTSVersion.VdbVer = nextLTSVersion.buildVersionStr()
}
return nextLTSVersion
}

// IsValidUpgradePath will return true if the current version is allowed to
// upgrade to targetVer. This will return false if the path isn't compatible.
func (i *Info) IsValidUpgradePath(targetVer string) (ok bool, failureReason string) {
Expand All @@ -165,36 +111,15 @@ func (i *Info) IsValidUpgradePath(targetVer string) (ok bool, failureReason stri
if i.IsEqual(t) {
return true, ""
}
// Check for a downgrade. Those are always blocked.
// Check for a downgrade.
if t.VdbMajor < i.VdbMajor ||
(t.VdbMajor == i.VdbMajor && t.VdbMinor < i.VdbMinor) ||
(t.VdbMajor == i.VdbMajor && t.VdbMinor == i.VdbMinor && t.VdbPatch < i.VdbPatch) {
return false,
fmt.Sprintf("Version '%s' to '%s' is a downgrade and is not supported",
i.VdbVer, t.VdbVer)
}
// Check if the major/minor versions are identical. It is okay to skip
// patch versions.
if i.IsEqualExceptPatch(t) {
return true, ""
}

// Check if the upgrade path is followed. You can only go from one released
// version to the next released version, but patches are allowed to be skipped.
nextVer, ok := UpgradePaths[i.Components]
if !ok {
// The version isn't found in the upgrade path. It must be a version
// newer that v12.0.4. Since from that point our release versions are
// more predictable, we can get the max version the current version
// can be upgraded to from the next LTS release version,
nextVer = i.getNextLTSVersion()
}
if t.IsOlderOrEqualExceptPatch(&nextVer) {
return true, ""
}
return false,
fmt.Sprintf("Version '%s' to '%s' is invalid because it skips '%s'",
i.VdbVer, t.VdbVer, nextVer.VdbVer)
return true, ""
}

// parseVersion will extract out the portions of a verson into 3 components:
Expand Down
23 changes: 6 additions & 17 deletions pkg/version/version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestAPIs(t *testing.T) {
}

var _ = Describe("version", func() {
It("should block some version transitions", func() {
It("should block downgrades", func() {
cur, ok := MakeInfoFromStr("v11.0.1")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v11.0.0")
Expand All @@ -38,32 +38,19 @@ var _ = Describe("version", func() {
Expect(ok).Should(BeFalse())
ok, _ = cur.IsValidUpgradePath("v11.1.0")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v11.0.2")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v11.2.2")
Expect(ok).Should(BeFalse()) // Fail because it skips v11.1.x
Expect(ok).Should(BeTrue())

cur, ok = MakeInfoFromStr("v12.0.3")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v12.0.4")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v23.3.0")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v23.4.0")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v24.1.0")
Expect(ok).Should(BeFalse())
ok, _ = cur.IsValidUpgradePath("v24.4.0")
Expect(ok).Should(BeFalse()) // Fail because it skips v23.4.0

cur, ok = MakeInfoFromStr("v23.3.0")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v23.4.0")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v24.2.0")
ok, _ = cur.IsValidUpgradePath("v12.0.2")
Expect(ok).Should(BeFalse())
ok, _ = cur.IsValidUpgradePath("v24.3.0")
Expect(ok).Should(BeFalse()) // Fail because it skips v23.4.0

cur, ok = MakeInfoFromStr("v23.4.0")
Expect(ok).Should(BeTrue())
Expand All @@ -72,7 +59,9 @@ var _ = Describe("version", func() {
ok, _ = cur.IsValidUpgradePath("v24.4.0")
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v25.1.0")
Expect(ok).Should(BeFalse()) // Fail because it skips v24.4.0
Expect(ok).Should(BeTrue())
ok, _ = cur.IsValidUpgradePath("v23.3.11")
Expect(ok).Should(BeFalse())
})

It("should return values for IsOlder", func() {
Expand Down

0 comments on commit a97d95f

Please sign in to comment.