Skip to content

Commit 5cdeb75

Browse files
DarrylWongsrosenberg
authored andcommitted
mixedversion: respect minimum bootstrap version when choosing predecessor
Previously, randomPredecessor would respect the minimum supported version when choosing a predecessor but not the minimum bootstrap version. This meant that it was possible for it to pick a non supported version and have the framework reject it later on. Instead, this change now passes the minimum bootstrap version to randomPredecessor and takes special care to pick a version that is supported.
1 parent dc4d39f commit 5cdeb75

File tree

3 files changed

+128
-22
lines changed

3 files changed

+128
-22
lines changed

pkg/cmd/roachtest/roachtestutil/mixedversion/mixedversion.go

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ type (
354354

355355
CustomOption func(*testOptions)
356356

357-
predecessorFunc func(*rand.Rand, *clusterupgrade.Version, *clusterupgrade.Version) (*clusterupgrade.Version, error)
357+
predecessorFunc func(*rand.Rand, *clusterupgrade.Version, *clusterupgrade.Version, *clusterupgrade.Version) (*clusterupgrade.Version, error)
358358

359359
// Test is the main struct callers of this package interact with.
360360
Test struct {
@@ -1048,18 +1048,18 @@ func (t *Test) chooseUpgradePath() ([]*clusterupgrade.Version, error) {
10481048
// function to change in case the rules around what upgrades are
10491049
// possible in CRDB change.
10501050
possiblePredecessorsFor := func(v *clusterupgrade.Version) ([]*clusterupgrade.Version, error) {
1051-
pred, err := t.options.predecessorFunc(t.prng, v, t.options.minimumSupportedVersion)
1051+
pred, err := t.options.predecessorFunc(t.prng, v, t.options.minimumSupportedVersion, t.options.minimumBootstrapVersion)
10521052
if err != nil {
10531053
return nil, err
10541054
}
10551055

1056-
// If the predecessor is older than the minimum bootstrap version,
1057-
// then it is not a legal predecessor.
1058-
if isOlderThanMinimumBootstrapVersion(pred) {
1056+
if !isAvailable(pred) {
10591057
return nil, nil
10601058
}
10611059

1062-
if !isAvailable(pred) {
1060+
// If the predecessor is older than the minimum bootstrap version,
1061+
// then it is not a legal predecessor.
1062+
if isOlderThanMinimumBootstrapVersion(pred) {
10631063
return nil, nil
10641064
}
10651065

@@ -1069,7 +1069,7 @@ func (t *Test) chooseUpgradePath() ([]*clusterupgrade.Version, error) {
10691069
return []*clusterupgrade.Version{pred}, nil
10701070
}
10711071

1072-
predPred, err := t.options.predecessorFunc(t.prng, pred, t.options.minimumSupportedVersion)
1072+
predPred, err := t.options.predecessorFunc(t.prng, pred, t.options.minimumSupportedVersion, t.options.minimumBootstrapVersion)
10731073
if err != nil {
10741074
return nil, err
10751075
}
@@ -1193,7 +1193,7 @@ func (t *Test) deploymentMode() DeploymentMode {
11931193
// always picks the latest predecessor for the given release version,
11941194
// ignoring the minimum supported version declared by the test.
11951195
func latestPredecessor(
1196-
_ *rand.Rand, v, minSupported *clusterupgrade.Version,
1196+
_ *rand.Rand, v, minSupported, minBootstrap *clusterupgrade.Version,
11971197
) (*clusterupgrade.Version, error) {
11981198
predecessor, err := release.LatestPredecessor(&v.Version)
11991199
if err != nil {
@@ -1207,47 +1207,100 @@ func latestPredecessor(
12071207
// picks a random predecessor for the given release version. If we are
12081208
// choosing a predecessor in the same series as the minimum supported
12091209
// version, special care is taken to select a random predecessor that
1210-
// is more recent that the minimum supported version.
1210+
// is more recent that the minimum supported version. Similarly, the
1211+
// same is done for the minimum bootstrap version. minSupported must be
1212+
// set but minBootstrap can be nil.
12111213
func randomPredecessor(
1212-
rng *rand.Rand, v, minSupported *clusterupgrade.Version,
1214+
rng *rand.Rand, v, minSupported, minBootstrap *clusterupgrade.Version,
12131215
) (*clusterupgrade.Version, error) {
12141216
predecessor, err := release.RandomPredecessor(rng, &v.Version)
12151217
if err != nil {
12161218
return nil, err
12171219
}
12181220

1219-
// If the minimum supported version is from a different release
1220-
// series, we can pick any random patch release.
12211221
predV := clusterupgrade.MustParseVersion(predecessor)
1222-
if predV.Series() != minSupported.Series() {
1222+
// minVersion the minimum version we make sure our selected predecessor satisfies.
1223+
// When choosing a predecessor version, we want to make sure we can run test hooks
1224+
// if possible on that release series.
1225+
minVersion := minSupported
1226+
// minBootstrapSeries is the release series of the minimum bootstrap version, is empty
1227+
// string if one is not set.
1228+
var minBootstrapSeries string
1229+
if minBootstrap != nil {
1230+
minBootstrapSeries = minBootstrap.Series()
1231+
}
1232+
1233+
// The minimum bootstrap version (mbv) is guaranteed to be older than or the same
1234+
// version as the minimum supported version (msv). This gives us the ordering of
1235+
// minBootstrap <= minSupported < currentVersion and the following 4 cases for what
1236+
// minVersion should be set to:
1237+
//
1238+
// 1. The predecessor series is a different series than the mbv and msv series, we can
1239+
// pick any random patch release.
1240+
// 2. The predecessor series is the same as the msv series, validate against the msv.
1241+
// 3. The predecessor series is the same as the mbv series, validate against the mbv.
1242+
// 4. The predecessor series is the same as both the mbv and msv series, validate against
1243+
// the msv since it's older.
1244+
//
1245+
// For example, consider a minimum bootstrap version (mbv) of v23.1.3 and a minimum
1246+
// supported version of v24.1.5 (msv). The framework may pick an upgrade path of:
1247+
// v23.1 -> v23.2 -> v24.1 -> 24.2. When picking a predecessor for:
1248+
//
1249+
// 1. v23.1: This is the same series as our mbv, so our predecessor needs to be
1250+
// at least v23.1.3 or the plan will not be valid. In this case, minVersion is
1251+
// set to the mbv. We can ignore the msv here since it is an older series so
1252+
// no patch release could satisfy it.
1253+
//
1254+
// 2. v23.2: This isn't the same series as either the msv or mbv, so we can ignore
1255+
// minVersion and pick any random patch release. Any patch from a series older than
1256+
// the msb/msv will never satisfy it, while any patch from a series older always
1257+
// satisfies it.
1258+
//
1259+
// 3. v24.1: This is the same series as our msv, so our predecessor needs to be
1260+
// at least v24.1.5. We could pick a patch older than that (e.g. v24.1.4) but then
1261+
// user hooks will not be run, and we lose out on testing coverage. In this case,
1262+
// minVersion is set to the msv.
1263+
//
1264+
// 4. v24.2: This is the same as v23.2 where neither the msv and mbv are the same
1265+
// series, so we can pick any random patch release.
1266+
if predV.Series() != minSupported.Series() && predV.Series() != minBootstrapSeries {
1267+
// If the predecessor version is from a different release series than both the minimum
1268+
// supported version and minimum bootstrap version, we can pick any random patch release.
1269+
// Case 1 above.
12231270
return predV, nil
1271+
} else if predV.Series() == minSupported.Series() {
1272+
// Case 2 and 4 above.
1273+
minVersion = minSupported
1274+
} else {
1275+
// Case 3 above.
1276+
minVersion = minBootstrap
12241277
}
12251278

12261279
// If the latest release of a series is a pre-release, we validate
12271280
// whether the minimum supported version is valid.
1228-
if predV.IsPrerelease() && !predV.AtLeast(minSupported) {
1281+
if predV.IsPrerelease() && !predV.AtLeast(minVersion) {
12291282
return nil, fmt.Errorf(
12301283
"latest release for %s (%s) is not sufficient for minimum supported version (%s)",
1231-
predV.Series(), predV, minSupported.Version,
1284+
predV.Series(), predV, minVersion.Version,
12321285
)
12331286
}
12341287

1235-
// If the patch version of `minSupported` is 0, it means that we
1288+
// If the patch version of `minVersion` is 0, it means that we
12361289
// can choose any patch release in the predecessor series. It is
12371290
// also safe to return `predV` here if the `minSupported` version is
12381291
// a pre-release: we already validated that `predV`is at least
12391292
// `minSupported` in check above.
1240-
if minSupported.Patch() == 0 {
1293+
if minVersion.Patch() == 0 {
12411294
return predV, nil
12421295
}
12431296

1244-
latestPred, err := latestPredecessor(rng, v, minSupported)
1297+
latestPred, err := latestPredecessor(rng, v, minVersion, minBootstrap)
12451298
if err != nil {
12461299
return nil, err
12471300
}
12481301

12491302
var supportedPatchReleases []*clusterupgrade.Version
1250-
for j := minSupported.Patch(); j <= latestPred.Patch(); j++ {
1303+
for j := minVersion.Patch(); j <= latestPred.Patch(); j++ {
12511304
supportedV := clusterupgrade.MustParseVersion(
12521305
fmt.Sprintf("%s.%d", predV.Major().String(), j),
12531306
)
@@ -1624,6 +1677,11 @@ func assertValidTest(test *Test, fatalFunc func(...interface{})) {
16241677
test.logger.Printf("WARN: overriding maxUpgrades, minimum bootstrap version (%s) allows for at most %d upgrades", minBootstrapVersion, maxUpgradesFromBootstrapVersion)
16251678
test.options.maxUpgrades = maxUpgradesFromBootstrapVersion
16261679
}
1680+
1681+
if msv.LessThan(minBootstrapVersion) {
1682+
test.logger.Printf("WARN: overriding minSupportedVersion, cannot be older than minimum bootstrap version (%s)", minBootstrapVersion)
1683+
test.options.minimumSupportedVersion = minBootstrapVersion
1684+
}
16271685
}
16281686
}
16291687

pkg/cmd/roachtest/roachtestutil/mixedversion/mixedversion_test.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ func Test_choosePreviousReleases(t *testing.T) {
290290
}
291291

292292
mvt := newTest(opts...)
293-
mvt.options.predecessorFunc = func(_ *rand.Rand, v, _ *clusterupgrade.Version) (*clusterupgrade.Version, error) {
293+
mvt.options.predecessorFunc = func(_ *rand.Rand, v, _, _ *clusterupgrade.Version) (*clusterupgrade.Version, error) {
294294
return testPredecessorMapping[v.Series()], tc.predecessorErr
295295
}
296296
mvt._arch = &tc.arch
@@ -334,6 +334,7 @@ func Test_randomPredecessor(t *testing.T) {
334334
name string
335335
v string
336336
minSupported string
337+
minBootstrap string
337338
expectedPredecessor string
338339
expectedError string
339340
}{
@@ -343,6 +344,13 @@ func Test_randomPredecessor(t *testing.T) {
343344
minSupported: "v24.1.0",
344345
expectedPredecessor: "v23.1.15",
345346
},
347+
{
348+
name: "minSupported and minBootstrap are from a different release series as predecessor",
349+
v: "v23.2.0",
350+
minSupported: "v24.1.0",
351+
minBootstrap: "v23.2.0",
352+
expectedPredecessor: "v23.1.15",
353+
},
346354
{
347355
name: "minSupported is same release series as predecessor, but patch is 0",
348356
v: "v23.2.0",
@@ -355,6 +363,20 @@ func Test_randomPredecessor(t *testing.T) {
355363
minSupported: "v23.1.8",
356364
expectedPredecessor: "v23.1.23",
357365
},
366+
{
367+
name: "minSupported is same release series as predecessor, but patch is 0 and minBootstrap is older release series",
368+
v: "v23.2.0",
369+
minSupported: "v23.1.0",
370+
minBootstrap: "v22.1.1",
371+
expectedPredecessor: "v23.1.15",
372+
},
373+
{
374+
name: "minSupported is same release series as predecessor and patch is not 0 and minBootstrap is older release series",
375+
v: "v23.2.0",
376+
minSupported: "v23.1.8",
377+
minBootstrap: "v22.1.1",
378+
expectedPredecessor: "v23.1.23",
379+
},
358380
{
359381
name: "latest predecessor is pre-release, but minimum supported is also the same version",
360382
v: "v24.3.0-alpha.00000000",
@@ -367,17 +389,43 @@ func Test_randomPredecessor(t *testing.T) {
367389
minSupported: "v24.2.0",
368390
expectedError: "latest release for 24.2 (v24.2.0-beta.1) is not sufficient for minimum supported version (v24.2.0)",
369391
},
392+
{
393+
name: "minBootstrap is same release series as predecessor, but patch is 0",
394+
v: "v23.2.0",
395+
minSupported: "v24.1.0",
396+
minBootstrap: "v23.1.0",
397+
expectedPredecessor: "v23.1.15",
398+
},
399+
{
400+
name: "minBootstrap is same release series as predecessor and patch is not 0",
401+
v: "v23.2.0",
402+
minSupported: "v24.1.0",
403+
minBootstrap: "v23.1.8",
404+
expectedPredecessor: "v23.1.23",
405+
},
406+
{
407+
name: "minBootstrap and minSupported are same release series as predecessor and patch is not 0",
408+
v: "v23.2.0",
409+
minSupported: "v23.1.15",
410+
minBootstrap: "v23.1.0",
411+
expectedPredecessor: "v23.1.19",
412+
},
370413
}
371414

372415
for _, tc := range testCases {
373416
t.Run(tc.name, func(t *testing.T) {
374417
var pred *clusterupgrade.Version
375418
var err error
376419
_ = release.WithReleaseData(testReleaseData, func() error {
420+
var minBootstrap *clusterupgrade.Version
421+
if tc.minBootstrap != "" {
422+
minBootstrap = clusterupgrade.MustParseVersion(tc.minBootstrap)
423+
}
377424
pred, err = randomPredecessor(
378425
newRand(),
379426
clusterupgrade.MustParseVersion(tc.v),
380427
clusterupgrade.MustParseVersion(tc.minSupported),
428+
minBootstrap,
381429
)
382430

383431
return err

pkg/cmd/roachtest/roachtestutil/mixedversion/planner_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ func boolP(b bool) *bool {
511511
// deterministic even as changes continue to happen in the
512512
// cockroach_releases.yaml file.
513513
func testPredecessorFunc(
514-
rng *rand.Rand, v, _ *clusterupgrade.Version,
514+
rng *rand.Rand, v, _, _ *clusterupgrade.Version,
515515
) (*clusterupgrade.Version, error) {
516516
pred, ok := testPredecessorMapping[v.Series()]
517517
if !ok {
@@ -585,7 +585,7 @@ func createDataDrivenMixedVersionTest(t *testing.T, args []datadriven.CmdArg) *T
585585
mvt._isLocal = isLocal
586586
}
587587
if predecessors != nil {
588-
mvt.options.predecessorFunc = func(_ *rand.Rand, v, _ *clusterupgrade.Version) (*clusterupgrade.Version, error) {
588+
mvt.options.predecessorFunc = func(_ *rand.Rand, v, _, _ *clusterupgrade.Version) (*clusterupgrade.Version, error) {
589589
if v.IsCurrent() {
590590
return predecessors[len(predecessors)-1], nil
591591
}

0 commit comments

Comments
 (0)