Skip to content

Commit

Permalink
server: Integrate version validation logic into tests
Browse files Browse the repository at this point in the history
  • Loading branch information
serathius committed Oct 8, 2021
1 parent bed9099 commit 6c8e721
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 22 deletions.
6 changes: 4 additions & 2 deletions server/etcdserver/api/membership/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ func (c *RaftCluster) Recover(onSet func(*zap.Logger, *semver.Version)) {
if c.downgradeInfo != nil {
d = &serverversion.DowngradeInfo{Enabled: c.downgradeInfo.Enabled, TargetVersion: c.downgradeInfo.TargetVersion}
}
serverversion.MustDetectDowngrade(c.lg, c.version, d)
sv := semver.Must(semver.NewVersion(version.Version))
serverversion.MustDetectDowngrade(c.lg, sv, c.version, d)
onSet(c.lg, c.version)

for _, m := range c.members {
Expand Down Expand Up @@ -541,7 +542,8 @@ func (c *RaftCluster) SetVersion(ver *semver.Version, onSet func(*zap.Logger, *s
}
oldVer := c.version
c.version = ver
serverversion.MustDetectDowngrade(c.lg, c.version, c.downgradeInfo)
sv := semver.Must(semver.NewVersion(version.Version))
serverversion.MustDetectDowngrade(c.lg, sv, c.version, c.downgradeInfo)
if c.v2store != nil {
mustSaveClusterVersionToStore(c.lg, c.v2store, ver)
}
Expand Down
19 changes: 9 additions & 10 deletions server/etcdserver/version/downgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,47 +34,46 @@ func (d *DowngradeInfo) GetTargetVersion() *semver.Version {

// isValidDowngrade verifies whether the cluster can be downgraded from verFrom to verTo
func isValidDowngrade(verFrom *semver.Version, verTo *semver.Version) bool {
return verTo.Equal(*AllowedDowngradeVersion(verFrom))
return verTo.Equal(*allowedDowngradeVersion(verFrom))
}

// MustDetectDowngrade will detect unexpected downgrade when the local server is recovered.
func MustDetectDowngrade(lg *zap.Logger, cv *semver.Version, d *DowngradeInfo) {
lv := semver.Must(semver.NewVersion(version.Version))
func MustDetectDowngrade(lg *zap.Logger, sv, cv *semver.Version, d *DowngradeInfo) {
// only keep major.minor version for comparison against cluster version
lv = &semver.Version{Major: lv.Major, Minor: lv.Minor}
sv = &semver.Version{Major: sv.Major, Minor: sv.Minor}

// if the cluster enables downgrade, check local version against downgrade target version.
if d != nil && d.Enabled && d.TargetVersion != "" {
if lv.Equal(*d.GetTargetVersion()) {
if sv.Equal(*d.GetTargetVersion()) {
if cv != nil {
lg.Info(
"cluster is downgrading to target version",
zap.String("target-cluster-version", d.TargetVersion),
zap.String("determined-cluster-version", version.Cluster(cv.String())),
zap.String("current-server-version", version.Version),
zap.String("current-server-version", sv.String()),
)
}
return
}
lg.Panic(
"invalid downgrade; server version is not allowed to join when downgrade is enabled",
zap.String("current-server-version", version.Version),
zap.String("current-server-version", sv.String()),
zap.String("target-cluster-version", d.TargetVersion),
)
}

// if the cluster disables downgrade, check local version against determined cluster version.
// the validation passes when local version is not less than cluster version
if cv != nil && lv.LessThan(*cv) {
if cv != nil && sv.LessThan(*cv) {
lg.Panic(
"invalid downgrade; server version is lower than determined cluster version",
zap.String("current-server-version", version.Version),
zap.String("current-server-version", sv.String()),
zap.String("determined-cluster-version", version.Cluster(cv.String())),
)
}
}

func AllowedDowngradeVersion(ver *semver.Version) *semver.Version {
func allowedDowngradeVersion(ver *semver.Version) *semver.Version {
// Todo: handle the case that downgrading from higher major version(e.g. downgrade from v4.0 to v3.x)
return &semver.Version{Major: ver.Major, Minor: ver.Minor - 1}
}
Expand Down
7 changes: 4 additions & 3 deletions server/etcdserver/version/downgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ func TestMustDetectDowngrade(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
lg := zaptest.NewLogger(t)
err := tryMustDetectDowngrade(lg, tt.clusterVersion, tt.downgrade)
sv := semver.Must(semver.NewVersion(version.Version))
err := tryMustDetectDowngrade(lg, sv, tt.clusterVersion, tt.downgrade)

if tt.success != (err == nil) {
t.Errorf("Unexpected status, got %q, wanted: %v", err, tt.success)
Expand All @@ -123,11 +124,11 @@ func TestMustDetectDowngrade(t *testing.T) {
}
}

func tryMustDetectDowngrade(lg *zap.Logger, cv *semver.Version, d *DowngradeInfo) (err interface{}) {
func tryMustDetectDowngrade(lg *zap.Logger, sv, cv *semver.Version, d *DowngradeInfo) (err interface{}) {
defer func() {
err = recover()
}()
MustDetectDowngrade(lg, cv, d)
MustDetectDowngrade(lg, sv, cv, d)
return err
}

Expand Down
2 changes: 1 addition & 1 deletion server/etcdserver/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (m *Manager) DowngradeValidate(ctx context.Context, targetVersion *semver.V
return err
}
cv := m.s.GetClusterVersion()
allowedTargetVersion := AllowedDowngradeVersion(cv)
allowedTargetVersion := allowedDowngradeVersion(cv)
if !targetVersion.Equal(*allowedTargetVersion) {
return ErrInvalidDowngradeTargetVersion
}
Expand Down
15 changes: 9 additions & 6 deletions server/etcdserver/version/version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func TestUpgradeThreeNodes(t *testing.T) {

func newCluster(lg *zap.Logger, memberCount int, ver semver.Version) *clusterMock {
cluster := &clusterMock{
lg: lg,
clusterVersion: ver,
members: make([]*memberMock, 0, memberCount),
}
Expand Down Expand Up @@ -99,13 +100,14 @@ func (c *clusterMock) StepMonitors() {
}

type clusterMock struct {
lg *zap.Logger
clusterVersion semver.Version
downgradeInfo *DowngradeInfo
members []*memberMock
}

func (c *clusterMock) DowngradeEnable(ver semver.Version) {
c.downgradeInfo = &DowngradeInfo{TargetVersion: ver.String(), Enabled: true}
func (c *clusterMock) Version() *Manager {
return NewManager(c.lg, c.members[0])
}

func (c *clusterMock) MembersVersions() map[string]*version.Versions {
Expand All @@ -120,9 +122,7 @@ func (c *clusterMock) MembersVersions() map[string]*version.Versions {
}

func (c *clusterMock) ReplaceMemberBinary(mid int, newServerVersion semver.Version) {
if newServerVersion.LessThan(c.clusterVersion) {
panic("Members cannot join clusters with higher version")
}
MustDetectDowngrade(c.lg, &c.members[mid].serverVersion, &c.clusterVersion, c.downgradeInfo)
c.members[mid].serverVersion = newServerVersion
}

Expand All @@ -146,7 +146,10 @@ func (m *memberMock) LinearizableReadNotify(ctx context.Context) error {
}

func (m *memberMock) DowngradeEnable(ctx context.Context, targetVersion *semver.Version) error {
m.cluster.downgradeInfo = nil
m.cluster.downgradeInfo = &DowngradeInfo{
TargetVersion: targetVersion.String(),
Enabled: true,
}
return nil
}

Expand Down

0 comments on commit 6c8e721

Please sign in to comment.