Skip to content

Commit a90bb7b

Browse files
committed
Adjust version checks on prerun
1 parent 5137c1b commit a90bb7b

3 files changed

Lines changed: 84 additions & 21 deletions

File tree

pkg/admin/prerun/version.go

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,31 @@ type versionFile struct {
3030

3131
const MAX_VERSION_SKEW = 2
3232

33+
// lastMinorForMajor defines the last minor version for each major version
34+
// before the next major begins.
35+
var lastMinorForMajor = map[int]int{
36+
4: 22,
37+
}
38+
39+
// linearVersion flattens a Major.Minor version into a single monotonically
40+
// increasing integer so that cross-major upgrades can be compared using
41+
// simple arithmetic.
42+
// It counts how many minor versions existed in all previous majors, then
43+
// adds the current minor. For example, major 4 had minors 0 through 22
44+
// (23 versions), so major 5 starts at offset 23:
45+
func linearVersion(ver versionMetadata) (int, error) {
46+
linear := 0
47+
for major := 4; major < ver.Major; major++ {
48+
last, ok := lastMinorForMajor[major]
49+
if !ok {
50+
return 0, fmt.Errorf("unknown major version %d in version map", major)
51+
}
52+
linear += last + 1
53+
}
54+
linear += ver.Minor
55+
return linear, nil
56+
}
57+
3358
func (hi *versionFile) BackupName() data.BackupName {
3459
return data.BackupName(fmt.Sprintf("%s_%s", hi.DeploymentID, hi.BootID))
3560
}
@@ -298,32 +323,39 @@ func GetVersionStringOfData() string {
298323
}
299324

300325
// checkVersionCompatibility compares versions of executable and existing data
301-
// to detect unsupported version changes
326+
// to detect unsupported version changes such as downgrades or upgrades that
327+
// skip too many minor versions. Uses linearVersion to handle cross-major
328+
// boundaries transparently (e.g. 4.22 -> 5.0 is treated as a single minor
329+
// version upgrade).
302330
func checkVersionCompatibility(execVer, dataVer versionMetadata) error {
303331
if execVer == dataVer {
304332
klog.InfoS("Executable and data versions are the same - continuing")
305333
return nil
306334
}
307335

308-
if execVer.Major != dataVer.Major {
309-
return fmt.Errorf("major versions are different: %d and %d", dataVer.Major, execVer.Major)
336+
execLinear, err := linearVersion(execVer)
337+
if err != nil {
338+
return err
339+
}
340+
dataLinear, err := linearVersion(dataVer)
341+
if err != nil {
342+
return err
310343
}
311344

312-
if execVer.Minor < dataVer.Minor {
313-
return fmt.Errorf("executable (%s) is older than existing data (%s): migrating data to older version is not supported", execVer.String(), dataVer.String())
345+
if execLinear < dataLinear {
346+
return fmt.Errorf("executable (%s) is older than existing data (%s): "+
347+
"migrating data to older version is not supported",
348+
execVer.String(), dataVer.String())
314349
}
315350

316-
if execVer.Minor > dataVer.Minor {
317-
versionSkew := execVer.Minor - dataVer.Minor
318-
if versionSkew <= MAX_VERSION_SKEW {
319-
klog.Infof("Executable is newer than data by %d minor versions, continuing", versionSkew)
320-
return nil
321-
} else {
322-
return fmt.Errorf("executable (%s) is too recent compared to existing data (%s): minor version difference is %d, maximum allowed difference is %d",
323-
execVer.String(), dataVer.String(), versionSkew, MAX_VERSION_SKEW)
324-
}
351+
skew := execLinear - dataLinear
352+
if skew > MAX_VERSION_SKEW {
353+
return fmt.Errorf("executable (%s) is too recent compared to existing data (%s): "+
354+
"version distance is %d, maximum allowed is %d",
355+
execVer.String(), dataVer.String(), skew, MAX_VERSION_SKEW)
325356
}
326357

327-
klog.InfoS("All version checks passed")
358+
klog.Infof("Version upgrade from %s to %s (distance %d), continuing",
359+
dataVer.String(), execVer.String(), skew)
328360
return nil
329361
}

pkg/admin/prerun/version_test.go

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ func TestCheckVersionDiff(t *testing.T) {
2020
dataVer: versionMetadata{Major: 4, Minor: 14},
2121
errExpected: false,
2222
},
23-
{
24-
name: "X versions must be the same",
25-
execVer: versionMetadata{Major: 4, Minor: 14},
26-
dataVer: versionMetadata{Major: 5, Minor: 14},
27-
errExpected: true,
28-
},
2923
{
3024
name: "binary must not be older than data",
3125
execVer: versionMetadata{Major: 4, Minor: 14},
@@ -50,6 +44,42 @@ func TestCheckVersionDiff(t *testing.T) {
5044
dataVer: versionMetadata{Major: 4, Minor: 13},
5145
errExpected: true,
5246
},
47+
{
48+
name: "cross-major upgrade 4.22 to 5.0 allowed (distance 1)",
49+
execVer: versionMetadata{Major: 5, Minor: 0},
50+
dataVer: versionMetadata{Major: 4, Minor: 22},
51+
errExpected: false,
52+
},
53+
{
54+
name: "cross-major upgrade 4.21 to 5.0 allowed (distance 2)",
55+
execVer: versionMetadata{Major: 5, Minor: 0},
56+
dataVer: versionMetadata{Major: 4, Minor: 21},
57+
errExpected: false,
58+
},
59+
{
60+
name: "cross-major upgrade 4.20 to 5.0 blocked (distance 3)",
61+
execVer: versionMetadata{Major: 5, Minor: 0},
62+
dataVer: versionMetadata{Major: 4, Minor: 20},
63+
errExpected: true,
64+
},
65+
{
66+
name: "cross-major downgrade 5.0 to 4.22 blocked",
67+
execVer: versionMetadata{Major: 4, Minor: 22},
68+
dataVer: versionMetadata{Major: 5, Minor: 0},
69+
errExpected: true,
70+
},
71+
{
72+
name: "cross-major upgrade 4.22 to 5.1 allowed (distance 2)",
73+
execVer: versionMetadata{Major: 5, Minor: 1},
74+
dataVer: versionMetadata{Major: 4, Minor: 22},
75+
errExpected: false,
76+
},
77+
{
78+
name: "same major upgrade 5.0 to 5.1 allowed",
79+
execVer: versionMetadata{Major: 5, Minor: 1},
80+
dataVer: versionMetadata{Major: 5, Minor: 0},
81+
errExpected: false,
82+
},
5383
}
5484

5585
for _, td := range testData {

test/bin/pyutils/generate_common_versions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
# Version map defining the last minor version for each major version.
2222
# Used for cross-major Y-1/Y-2 calculations (e.g., 5.0's Y-1 is 4.22).
23+
# Authoritative source: lastMinorForMajor in pkg/admin/prerun/version.go
2324
VERSION_MAP = {
2425
4: {'last_minor': 22}
2526
}

0 commit comments

Comments
 (0)