Merge pull request #14107 from ahrtr/version_refactor_20220613

Get all constant etcd versions defined in a centralized place
This commit is contained in:
Marek Siarkowicz 2022-06-13 10:31:46 +02:00 committed by GitHub
commit 4592af25ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 295 additions and 204 deletions

View File

@ -7,16 +7,20 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.5.2
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/stretchr/testify v1.7.0
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1
google.golang.org/grpc v1.41.0
)
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
golang.org/x/text v0.3.5 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
// Bad imports are sometimes causing attempts to pull that code.

View File

@ -13,6 +13,7 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@ -52,12 +53,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -148,11 +151,13 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -33,6 +33,19 @@ var (
GitSHA = "Not provided (use ./build instead of go build)"
)
// Get all constant versions defined in a centralized place.
var (
V3_0 = semver.Version{Major: 3, Minor: 0}
V3_1 = semver.Version{Major: 3, Minor: 1}
V3_2 = semver.Version{Major: 3, Minor: 2}
V3_3 = semver.Version{Major: 3, Minor: 3}
V3_4 = semver.Version{Major: 3, Minor: 4}
V3_5 = semver.Version{Major: 3, Minor: 5}
V3_6 = semver.Version{Major: 3, Minor: 6}
V3_7 = semver.Version{Major: 3, Minor: 7}
V4_0 = semver.Version{Major: 4, Minor: 0}
)
func init() {
ver, err := semver.NewVersion(Version)
if err == nil {
@ -55,3 +68,15 @@ func Cluster(v string) string {
}
return fmt.Sprintf("%s.%s", vs[0], vs[1])
}
func Compare(ver1, ver2 semver.Version) int {
return ver1.Compare(ver2)
}
func LessThan(ver1, ver2 semver.Version) bool {
return ver1.LessThan(ver2)
}
func Equal(ver1, ver2 semver.Version) bool {
return ver1.Equal(ver2)
}

View File

@ -0,0 +1,85 @@
// Copyright 2022 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package version
import (
"testing"
"github.com/coreos/go-semver/semver"
"github.com/stretchr/testify/assert"
)
func TestVersionCompare(t *testing.T) {
cases := []struct {
name string
ver1 semver.Version
ver2 semver.Version
expectedCompareResult int
expectedLessThanResult bool
expectedEqualResult bool
}{
{
name: "ver1 should be great than ver2",
ver1: V3_5,
ver2: V3_4,
expectedCompareResult: 1,
expectedLessThanResult: false,
expectedEqualResult: false,
},
{
name: "ver1(4.0) should be great than ver2",
ver1: V4_0,
ver2: V3_7,
expectedCompareResult: 1,
expectedLessThanResult: false,
expectedEqualResult: false,
},
{
name: "ver1 should be less than ver2",
ver1: V3_5,
ver2: V3_6,
expectedCompareResult: -1,
expectedLessThanResult: true,
expectedEqualResult: false,
},
{
name: "ver1 should be less than ver2 (4.0)",
ver1: V3_5,
ver2: V4_0,
expectedCompareResult: -1,
expectedLessThanResult: true,
expectedEqualResult: false,
},
{
name: "ver1 should be equal to ver2",
ver1: V3_5,
ver2: V3_5,
expectedCompareResult: 0,
expectedLessThanResult: false,
expectedEqualResult: true,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
compareResult := Compare(tc.ver1, tc.ver2)
lessThanResult := LessThan(tc.ver1, tc.ver2)
equalResult := Equal(tc.ver1, tc.ver2)
assert.Equal(t, tc.expectedCompareResult, compareResult)
assert.Equal(t, tc.expectedLessThanResult, lessThanResult)
assert.Equal(t, tc.expectedEqualResult, equalResult)
})
}
}

View File

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra"
"go.uber.org/zap"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/pkg/v3/cobrautl"
"go.etcd.io/etcd/server/v3/storage/backend"
"go.etcd.io/etcd/server/v3/storage/datadir"
@ -86,7 +87,7 @@ func (o *migrateOptions) Config() (*migrateConfig, error) {
if err != nil {
return nil, fmt.Errorf("failed to parse target version: %v", err)
}
if c.targetVersion.LessThan(schema.V3_5) {
if c.targetVersion.LessThan(version.V3_5) {
return nil, fmt.Errorf(`target version %q not supported. Minimal "3.5"`, storageVersionToString(c.targetVersion))
}
@ -143,7 +144,7 @@ func migrateForce(lg *zap.Logger, tx backend.BatchTx, target *semver.Version) {
tx.LockOutsideApply()
defer tx.Unlock()
// Storage version is only supported since v3.6
if target.LessThan(schema.V3_6) {
if target.LessThan(version.V3_6) {
schema.UnsafeClearStorageVersion(tx)
lg.Warn("forcefully cleared storage version")
} else {

View File

@ -12,12 +12,6 @@ import (
"go.etcd.io/etcd/api/v3/version"
)
var (
V3_0 = semver.Version{Major: 3, Minor: 0}
V3_5 = semver.Version{Major: 3, Minor: 5}
V3_6 = semver.Version{Major: 3, Minor: 6}
)
func TestMemberMinimalVersion(t *testing.T) {
tests := []struct {
memberVersions map[string]*version.Versions
@ -69,25 +63,25 @@ func TestDecideStorageVersion(t *testing.T) {
},
{
name: "Should set storage version if cluster version is set",
clusterVersion: &V3_5,
expectStorageVersion: &V3_5,
clusterVersion: &version.V3_5,
expectStorageVersion: &version.V3_5,
},
{
name: "No action if storage version was already set",
storageVersion: &V3_5,
expectStorageVersion: &V3_5,
storageVersion: &version.V3_5,
expectStorageVersion: &version.V3_5,
},
{
name: "No action if storage version equals cluster version",
clusterVersion: &V3_5,
storageVersion: &V3_5,
expectStorageVersion: &V3_5,
clusterVersion: &version.V3_5,
storageVersion: &version.V3_5,
expectStorageVersion: &version.V3_5,
},
{
name: "Should set storage version to cluster version",
clusterVersion: &V3_6,
storageVersion: &V3_5,
expectStorageVersion: &V3_6,
clusterVersion: &version.V3_6,
storageVersion: &version.V3_5,
expectStorageVersion: &version.V3_6,
},
}
@ -168,7 +162,7 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
}{
{
name: "Default to 3.0 if there are no members",
expectClusterVersion: &V3_0,
expectClusterVersion: &version.V3_0,
},
{
name: "Should pick lowest server version from members",
@ -176,7 +170,7 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.7.0", Server: "3.6.0"},
"b": {Cluster: "3.4.0", Server: "3.5.0"},
},
expectClusterVersion: &V3_5,
expectClusterVersion: &version.V3_5,
},
{
name: "Sets minimal version when member has broken version",
@ -184,7 +178,7 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.7.0", Server: "3.6.0"},
"b": {Cluster: "xxxx", Server: "yyyy"},
},
expectClusterVersion: &V3_0,
expectClusterVersion: &version.V3_0,
},
{
name: "Should pick lowest server version from members (cv already set)",
@ -192,8 +186,8 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.7.0", Server: "3.6.0"},
"b": {Cluster: "3.4.0", Server: "3.5.0"},
},
clusterVersion: &V3_5,
expectClusterVersion: &V3_5,
clusterVersion: &version.V3_5,
expectClusterVersion: &version.V3_5,
},
{
name: "Should upgrade cluster version if all members have upgraded (have higher server version)",
@ -201,8 +195,8 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.5.0", Server: "3.6.0"},
"b": {Cluster: "3.5.0", Server: "3.6.0"},
},
clusterVersion: &V3_5,
expectClusterVersion: &V3_6,
clusterVersion: &version.V3_5,
expectClusterVersion: &version.V3_6,
},
{
name: "Should downgrade cluster version if downgrade is set to allow older members to join",
@ -210,9 +204,9 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.6.0", Server: "3.6.0"},
"b": {Cluster: "3.6.0", Server: "3.6.0"},
},
clusterVersion: &V3_6,
clusterVersion: &version.V3_6,
downgrade: &DowngradeInfo{TargetVersion: "3.5.0", Enabled: true},
expectClusterVersion: &V3_5,
expectClusterVersion: &version.V3_5,
},
{
name: "Should maintain downgrade target version to allow older members to join",
@ -220,9 +214,9 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.5.0", Server: "3.6.0"},
"b": {Cluster: "3.5.0", Server: "3.6.0"},
},
clusterVersion: &V3_5,
clusterVersion: &version.V3_5,
downgrade: &DowngradeInfo{TargetVersion: "3.5.0", Enabled: true},
expectClusterVersion: &V3_5,
expectClusterVersion: &version.V3_5,
},
{
name: "Don't downgrade below supported range",
@ -230,9 +224,9 @@ func TestUpdateClusterVersionIfNeeded(t *testing.T) {
"a": {Cluster: "3.5.0", Server: "3.6.0"},
"b": {Cluster: "3.5.0", Server: "3.6.0"},
},
clusterVersion: &V3_5,
clusterVersion: &version.V3_5,
downgrade: &DowngradeInfo{TargetVersion: "3.4.0", Enabled: true},
expectClusterVersion: &V3_5,
expectClusterVersion: &version.V3_5,
},
}
@ -335,25 +329,25 @@ func TestUpdateStorageVersionIfNeeded(t *testing.T) {
},
{
name: "Should set storage version if cluster version is set",
clusterVersion: &V3_5,
expectStorageVersion: &V3_5,
clusterVersion: &version.V3_5,
expectStorageVersion: &version.V3_5,
},
{
name: "No action if storage version was already set",
storageVersion: &V3_5,
expectStorageVersion: &V3_5,
storageVersion: &version.V3_5,
expectStorageVersion: &version.V3_5,
},
{
name: "No action if storage version equals cluster version",
clusterVersion: &V3_5,
storageVersion: &V3_5,
expectStorageVersion: &V3_5,
clusterVersion: &version.V3_5,
storageVersion: &version.V3_5,
expectStorageVersion: &version.V3_5,
},
{
name: "Should set storage version to cluster version",
clusterVersion: &V3_6,
storageVersion: &V3_5,
expectStorageVersion: &V3_6,
clusterVersion: &version.V3_6,
storageVersion: &version.V3_5,
expectStorageVersion: &version.V3_6,
},
}

View File

@ -28,87 +28,83 @@ import (
"go.etcd.io/etcd/api/v3/version"
)
var (
V3_7 = semver.Version{Major: 3, Minor: 7}
)
func TestUpgradeSingleNode(t *testing.T) {
lg := zaptest.NewLogger(t)
c := newCluster(lg, 1, V3_6)
c := newCluster(lg, 1, version.V3_6)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 1, V3_6), c)
assert.Equal(t, newCluster(lg, 1, version.V3_6), c)
c.ReplaceMemberBinary(0, V3_7)
c.ReplaceMemberBinary(0, version.V3_7)
c.StepMonitors()
c.StepMonitors()
assert.Equal(t, newCluster(lg, 1, V3_7), c)
assert.Equal(t, newCluster(lg, 1, version.V3_7), c)
}
func TestUpgradeThreeNodes(t *testing.T) {
lg := zaptest.NewLogger(t)
c := newCluster(lg, 3, V3_6)
c := newCluster(lg, 3, version.V3_6)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 3, V3_6), c)
assert.Equal(t, newCluster(lg, 3, version.V3_6), c)
c.ReplaceMemberBinary(0, V3_7)
c.ReplaceMemberBinary(0, version.V3_7)
c.StepMonitors()
c.ReplaceMemberBinary(1, V3_7)
c.ReplaceMemberBinary(1, version.V3_7)
c.StepMonitors()
c.ReplaceMemberBinary(2, V3_7)
c.ReplaceMemberBinary(2, version.V3_7)
c.StepMonitors()
c.StepMonitors()
assert.Equal(t, newCluster(lg, 3, V3_7), c)
assert.Equal(t, newCluster(lg, 3, version.V3_7), c)
}
func TestDowngradeSingleNode(t *testing.T) {
lg := zaptest.NewLogger(t)
c := newCluster(lg, 1, V3_6)
c := newCluster(lg, 1, version.V3_6)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 1, V3_6), c)
assert.Equal(t, newCluster(lg, 1, version.V3_6), c)
assert.NoError(t, c.Version().DowngradeEnable(context.Background(), &V3_5))
assert.NoError(t, c.Version().DowngradeEnable(context.Background(), &version.V3_5))
c.StepMonitors()
assert.Equal(t, V3_5, c.clusterVersion)
assert.Equal(t, version.V3_5, c.clusterVersion)
c.ReplaceMemberBinary(0, V3_5)
c.ReplaceMemberBinary(0, version.V3_5)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 1, V3_5), c)
assert.Equal(t, newCluster(lg, 1, version.V3_5), c)
}
func TestDowngradeThreeNode(t *testing.T) {
lg := zaptest.NewLogger(t)
c := newCluster(lg, 3, V3_6)
c := newCluster(lg, 3, version.V3_6)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 3, V3_6), c)
assert.Equal(t, newCluster(lg, 3, version.V3_6), c)
assert.NoError(t, c.Version().DowngradeEnable(context.Background(), &V3_5))
assert.NoError(t, c.Version().DowngradeEnable(context.Background(), &version.V3_5))
c.StepMonitors()
assert.Equal(t, V3_5, c.clusterVersion)
assert.Equal(t, version.V3_5, c.clusterVersion)
c.ReplaceMemberBinary(0, V3_5)
c.ReplaceMemberBinary(0, version.V3_5)
c.StepMonitors()
c.ReplaceMemberBinary(1, V3_5)
c.ReplaceMemberBinary(1, version.V3_5)
c.StepMonitors()
c.ReplaceMemberBinary(2, V3_5)
c.ReplaceMemberBinary(2, version.V3_5)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 3, V3_5), c)
assert.Equal(t, newCluster(lg, 3, version.V3_5), c)
}
func TestNewerMemberCanReconnectDuringDowngrade(t *testing.T) {
lg := zaptest.NewLogger(t)
c := newCluster(lg, 3, V3_6)
c := newCluster(lg, 3, version.V3_6)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 3, V3_6), c)
assert.Equal(t, newCluster(lg, 3, version.V3_6), c)
assert.NoError(t, c.Version().DowngradeEnable(context.Background(), &V3_5))
assert.NoError(t, c.Version().DowngradeEnable(context.Background(), &version.V3_5))
c.StepMonitors()
assert.Equal(t, V3_5, c.clusterVersion)
assert.Equal(t, version.V3_5, c.clusterVersion)
c.ReplaceMemberBinary(0, V3_5)
c.ReplaceMemberBinary(0, version.V3_5)
c.StepMonitors()
c.MemberCrashes(2)
@ -116,12 +112,12 @@ func TestNewerMemberCanReconnectDuringDowngrade(t *testing.T) {
c.MemberReconnects(2)
c.StepMonitors()
c.ReplaceMemberBinary(1, V3_5)
c.ReplaceMemberBinary(1, version.V3_5)
c.StepMonitors()
c.ReplaceMemberBinary(2, V3_5)
c.ReplaceMemberBinary(2, version.V3_5)
c.StepMonitors()
assert.Equal(t, newCluster(lg, 3, V3_5), c)
assert.Equal(t, newCluster(lg, 3, version.V3_5), c)
}
func newCluster(lg *zap.Logger, memberCount int, ver semver.Version) *clusterMock {

View File

@ -25,6 +25,7 @@ import (
"github.com/coreos/go-semver/semver"
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/server/v3/lease/leasepb"
"go.etcd.io/etcd/server/v3/storage/backend"
"go.etcd.io/etcd/server/v3/storage/schema"
@ -37,8 +38,6 @@ const NoLease = LeaseID(0)
// MaxLeaseTTL is the maximum lease TTL value
const MaxLeaseTTL = 9000000000
var v3_6 = semver.Version{Major: 3, Minor: 6}
var (
forever = time.Time{}
@ -381,11 +380,11 @@ func (le *lessor) Checkpoint(id LeaseID, remainingTTL int64) error {
func (le *lessor) shouldPersistCheckpoints() bool {
cv := le.cluster.Version()
return le.checkpointPersist || (cv != nil && greaterOrEqual(*cv, v3_6))
return le.checkpointPersist || (cv != nil && greaterOrEqual(*cv, version.V3_6))
}
func greaterOrEqual(first, second semver.Version) bool {
return !first.LessThan(second)
return !version.LessThan(first, second)
}
// Renew renews an existing lease. If the given lease does not exist or

View File

@ -18,6 +18,7 @@ import (
"fmt"
"github.com/coreos/go-semver/semver"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/server/v3/storage/backend"
"go.uber.org/zap"
)
@ -102,7 +103,7 @@ func (s migrationStep) unsafeExecute(lg *zap.Logger, tx backend.BatchTx) error {
return err
}
// Storage version is available since v3.6, downgrading target v3.5 should clean this field.
if !s.target.LessThan(V3_6) {
if !s.target.LessThan(version.V3_6) {
UnsafeSetStorageVersion(tx, &s.target)
}
return nil

View File

@ -21,15 +21,12 @@ import (
"github.com/coreos/go-semver/semver"
"github.com/stretchr/testify/assert"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/server/v3/storage/backend"
betesting "go.etcd.io/etcd/server/v3/storage/backend/testing"
"go.uber.org/zap/zaptest"
)
var (
V4_0 = semver.Version{Major: 4, Minor: 0}
)
func TestNewPlan(t *testing.T) {
tcs := []struct {
name string
@ -42,25 +39,25 @@ func TestNewPlan(t *testing.T) {
}{
{
name: "Update v3.5 to v3.6 should work",
current: V3_5,
target: V3_6,
current: version.V3_5,
target: version.V3_6,
},
{
name: "Downgrade v3.6 to v3.5 should fail as downgrades are not yet supported",
current: V3_6,
target: V3_5,
current: version.V3_6,
target: version.V3_5,
},
{
name: "Upgrade v3.6 to v3.7 should fail as v3.7 is unknown",
current: V3_6,
target: V3_7,
current: version.V3_6,
target: version.V3_7,
expectError: true,
expectErrorMsg: `version "3.7.0" is not supported`,
},
{
name: "Upgrade v3.6 to v4.0 as major version changes are unsupported",
current: V3_6,
target: V4_0,
current: version.V3_6,
target: version.V4_0,
expectError: true,
expectErrorMsg: "changing major storage version is not supported",
},
@ -152,7 +149,7 @@ func TestMigrationStepExecute(t *testing.T) {
{
name: "Downgrade below to below v3.6 doesn't leave storage version as it was not supported then",
currentVersion: semver.Version{Major: 3, Minor: 6},
changes: schemaChanges[V3_6],
changes: schemaChanges[version.V3_6],
isUpgrade: false,
expectVersion: nil,
},

View File

@ -24,11 +24,6 @@ import (
"go.etcd.io/etcd/server/v3/storage/backend"
)
var (
V3_5 = semver.Version{Major: 3, Minor: 5}
V3_6 = semver.Version{Major: 3, Minor: 6}
)
// Validate checks provided backend to confirm that schema used is supported.
func Validate(lg *zap.Logger, tx backend.ReadTx) error {
tx.Lock()
@ -108,7 +103,7 @@ func UnsafeDetectSchemaVersion(lg *zap.Logger, tx backend.ReadTx) (v semver.Vers
if term == 0 {
return v, fmt.Errorf("missing term information")
}
return V3_5, nil
return version.V3_5, nil
}
func schemaChangesForVersion(v semver.Version, isUpgrade bool) ([]schemaChange, error) {
@ -132,7 +127,7 @@ var (
// schemaChanges list changes that were introduced in a particular version.
// schema was introduced in v3.6 as so its changes were not tracked before.
schemaChanges = map[semver.Version][]schemaChange{
V3_6: {
version.V3_6: {
addNewField(Meta, MetaStorageVersionName, emptyStorageVersion),
},
}

View File

@ -22,6 +22,7 @@ import (
"github.com/stretchr/testify/assert"
"go.etcd.io/etcd/api/v3/etcdserverpb"
"go.etcd.io/etcd/api/v3/membershippb"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/raft/v3/raftpb"
"go.etcd.io/etcd/server/v3/storage/backend"
betesting "go.etcd.io/etcd/server/v3/storage/backend/testing"
@ -30,11 +31,6 @@ import (
"go.uber.org/zap"
)
var (
V3_4 = semver.Version{Major: 3, Minor: 4}
V3_7 = semver.Version{Major: 3, Minor: 7}
)
func TestValidate(t *testing.T) {
tcs := []struct {
name string
@ -48,23 +44,23 @@ func TestValidate(t *testing.T) {
// For storage to be considered v3.5 it have both confstate and term key set.
{
name: `V3.4 schema is correct`,
version: V3_4,
version: version.V3_4,
},
{
name: `V3.5 schema without confstate and term fields is correct`,
version: V3_5,
version: version.V3_5,
overrideKeys: func(tx backend.BatchTx) {},
},
{
name: `V3.5 schema without term field is correct`,
version: V3_5,
version: version.V3_5,
overrideKeys: func(tx backend.BatchTx) {
MustUnsafeSaveConfStateToBackend(zap.NewNop(), tx, &raftpb.ConfState{})
},
},
{
name: `V3.5 schema with all fields is correct`,
version: V3_5,
version: version.V3_5,
overrideKeys: func(tx backend.BatchTx) {
MustUnsafeSaveConfStateToBackend(zap.NewNop(), tx, &raftpb.ConfState{})
UnsafeUpdateConsistentIndex(tx, 1, 1)
@ -72,11 +68,11 @@ func TestValidate(t *testing.T) {
},
{
name: `V3.6 schema is correct`,
version: V3_6,
version: version.V3_6,
},
{
name: `V3.7 schema is unknown and should return error`,
version: V3_7,
version: version.V3_7,
expectError: true,
expectErrorMsg: `version "3.7.0" is not supported`,
},
@ -116,68 +112,68 @@ func TestMigrate(t *testing.T) {
// For storage to be considered v3.5 it have both confstate and term key set.
{
name: `Upgrading v3.5 to v3.6 should be rejected if confstate is not set`,
version: V3_5,
version: version.V3_5,
overrideKeys: func(tx backend.BatchTx) {},
targetVersion: V3_6,
targetVersion: version.V3_6,
expectVersion: nil,
expectError: true,
expectErrorMsg: `cannot detect storage schema version: missing confstate information`,
},
{
name: `Upgrading v3.5 to v3.6 should be rejected if term is not set`,
version: V3_5,
version: version.V3_5,
overrideKeys: func(tx backend.BatchTx) {
MustUnsafeSaveConfStateToBackend(zap.NewNop(), tx, &raftpb.ConfState{})
},
targetVersion: V3_6,
targetVersion: version.V3_6,
expectVersion: nil,
expectError: true,
expectErrorMsg: `cannot detect storage schema version: missing term information`,
},
{
name: `Upgrading v3.5 to v3.6 should succeed; all required fields are set`,
version: V3_5,
targetVersion: V3_6,
expectVersion: &V3_6,
version: version.V3_5,
targetVersion: version.V3_6,
expectVersion: &version.V3_6,
},
{
name: `Migrate on same v3.5 version passes and doesn't set storage version'`,
version: V3_5,
targetVersion: V3_5,
version: version.V3_5,
targetVersion: version.V3_5,
expectVersion: nil,
},
{
name: `Migrate on same v3.6 version passes`,
version: V3_6,
targetVersion: V3_6,
expectVersion: &V3_6,
version: version.V3_6,
targetVersion: version.V3_6,
expectVersion: &version.V3_6,
},
{
name: `Migrate on same v3.7 version passes`,
version: V3_7,
targetVersion: V3_7,
expectVersion: &V3_7,
version: version.V3_7,
targetVersion: version.V3_7,
expectVersion: &version.V3_7,
},
{
name: "Upgrading 3.6 to v3.7 is not supported",
version: V3_6,
targetVersion: V3_7,
expectVersion: &V3_6,
version: version.V3_6,
targetVersion: version.V3_7,
expectVersion: &version.V3_6,
expectError: true,
expectErrorMsg: `cannot create migration plan: version "3.7.0" is not supported`,
},
{
name: "Downgrading v3.7 to v3.6 is not supported",
version: V3_7,
targetVersion: V3_6,
expectVersion: &V3_7,
version: version.V3_7,
targetVersion: version.V3_6,
expectVersion: &version.V3_7,
expectError: true,
expectErrorMsg: `cannot create migration plan: version "3.7.0" is not supported`,
},
{
name: "Downgrading v3.6 to v3.5 works as there are no v3.6 wal entries",
version: V3_6,
targetVersion: V3_5,
version: version.V3_6,
targetVersion: version.V3_5,
walEntries: []etcdserverpb.InternalRaftRequest{
{Range: &etcdserverpb.RangeRequest{Key: []byte("\x00"), RangeEnd: []byte("\xff")}},
},
@ -185,19 +181,19 @@ func TestMigrate(t *testing.T) {
},
{
name: "Downgrading v3.6 to v3.5 fails if there are newer WAL entries",
version: V3_6,
targetVersion: V3_5,
version: version.V3_6,
targetVersion: version.V3_5,
walEntries: []etcdserverpb.InternalRaftRequest{
{ClusterVersionSet: &membershippb.ClusterVersionSetRequest{Ver: "3.6.0"}},
},
expectVersion: &V3_6,
expectVersion: &version.V3_6,
expectError: true,
expectErrorMsg: "cannot downgrade storage, WAL contains newer entries",
},
{
name: "Downgrading v3.5 to v3.4 is not supported as schema was introduced in v3.6",
version: V3_5,
targetVersion: V3_4,
version: version.V3_5,
targetVersion: version.V3_4,
expectVersion: nil,
expectError: true,
expectErrorMsg: `cannot create migration plan: version "3.5.0" is not supported`,
@ -236,7 +232,7 @@ func TestMigrateIsReversible(t *testing.T) {
state map[string]string
}{
{
initialVersion: V3_5,
initialVersion: version.V3_5,
state: map[string]string{
"confState": `{"auto_leave":false}`,
"consistent_index": "\x00\x00\x00\x00\x00\x00\x00\x01",
@ -244,7 +240,7 @@ func TestMigrateIsReversible(t *testing.T) {
},
},
{
initialVersion: V3_6,
initialVersion: version.V3_6,
state: map[string]string{
"confState": `{"auto_leave":false}`,
"consistent_index": "\x00\x00\x00\x00\x00\x00\x00\x01",
@ -297,7 +293,7 @@ func TestMigrateIsReversible(t *testing.T) {
}
}
func setupBackendData(t *testing.T, version semver.Version, overrideKeys func(tx backend.BatchTx)) string {
func setupBackendData(t *testing.T, ver semver.Version, overrideKeys func(tx backend.BatchTx)) string {
t.Helper()
be, tmpPath := betesting.NewTmpBackend(t, time.Microsecond, 10)
tx := be.BatchTx()
@ -309,19 +305,19 @@ func setupBackendData(t *testing.T, version semver.Version, overrideKeys func(tx
if overrideKeys != nil {
overrideKeys(tx)
} else {
switch version {
case V3_4:
case V3_5:
switch ver {
case version.V3_4:
case version.V3_5:
MustUnsafeSaveConfStateToBackend(zap.NewNop(), tx, &raftpb.ConfState{})
UnsafeUpdateConsistentIndex(tx, 1, 1)
case V3_6:
case version.V3_6:
MustUnsafeSaveConfStateToBackend(zap.NewNop(), tx, &raftpb.ConfState{})
UnsafeUpdateConsistentIndex(tx, 1, 1)
UnsafeSetStorageVersion(tx, &V3_6)
case V3_7:
UnsafeSetStorageVersion(tx, &version.V3_6)
case version.V3_7:
MustUnsafeSaveConfStateToBackend(zap.NewNop(), tx, &raftpb.ConfState{})
UnsafeUpdateConsistentIndex(tx, 1, 1)
UnsafeSetStorageVersion(tx, &V3_7)
UnsafeSetStorageVersion(tx, &version.V3_7)
tx.UnsafePut(Meta, []byte("future-key"), []byte(""))
default:
t.Fatalf("Unsupported storage version")

View File

@ -23,20 +23,12 @@ import (
"github.com/stretchr/testify/assert"
"go.etcd.io/etcd/api/v3/etcdserverpb"
"go.etcd.io/etcd/api/v3/membershippb"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/pkg/v3/pbutil"
"go.etcd.io/etcd/raft/v3/raftpb"
"google.golang.org/protobuf/reflect/protoreflect"
)
var (
V3_0 = semver.Version{Major: 3, Minor: 0}
V3_1 = semver.Version{Major: 3, Minor: 1}
V3_3 = semver.Version{Major: 3, Minor: 3}
V3_4 = semver.Version{Major: 3, Minor: 4}
V3_5 = semver.Version{Major: 3, Minor: 5}
V3_6 = semver.Version{Major: 3, Minor: 6}
)
func TestEtcdVersionFromEntry(t *testing.T) {
raftReq := etcdserverpb.InternalRaftRequest{Header: &etcdserverpb.RequestHeader{AuthRevision: 1}}
normalRequestData := pbutil.MustMarshal(&raftReq)
@ -63,7 +55,7 @@ func TestEtcdVersionFromEntry(t *testing.T) {
Type: raftpb.EntryNormal,
Data: normalRequestData,
},
expect: &V3_1,
expect: &version.V3_1,
},
{
name: "Setting cluster version implies version within",
@ -73,7 +65,7 @@ func TestEtcdVersionFromEntry(t *testing.T) {
Type: raftpb.EntryNormal,
Data: clusterVersionV3_6Data,
},
expect: &V3_6,
expect: &version.V3_6,
},
{
name: "Using ConfigChange implies v3.4",
@ -83,7 +75,7 @@ func TestEtcdVersionFromEntry(t *testing.T) {
Type: raftpb.EntryConfChange,
Data: confChangeData,
},
expect: &V3_0,
expect: &version.V3_0,
},
{
name: "Using ConfigChangeV2 implies v3.4",
@ -93,7 +85,7 @@ func TestEtcdVersionFromEntry(t *testing.T) {
Type: raftpb.EntryConfChangeV2,
Data: confChangeV2Data,
},
expect: &V3_4,
expect: &version.V3_4,
},
}
for _, tc := range tcs {
@ -118,52 +110,52 @@ func TestEtcdVersionFromMessage(t *testing.T) {
{
name: "Empty RequestHeader impies v3.0",
input: &etcdserverpb.RequestHeader{},
expect: &V3_0,
expect: &version.V3_0,
},
{
name: "RequestHeader AuthRevision field set implies v3.5",
input: &etcdserverpb.RequestHeader{AuthRevision: 1},
expect: &V3_1,
expect: &version.V3_1,
},
{
name: "RequestHeader Username set implies v3.0",
input: &etcdserverpb.RequestHeader{Username: "Alice"},
expect: &V3_0,
expect: &version.V3_0,
},
{
name: "When two fields are set take higher version",
input: &etcdserverpb.RequestHeader{AuthRevision: 1, Username: "Alice"},
expect: &V3_1,
expect: &version.V3_1,
},
{
name: "Setting a RequestHeader AuthRevision in subfield implies v3.1",
input: &etcdserverpb.InternalRaftRequest{Header: &etcdserverpb.RequestHeader{AuthRevision: 1}},
expect: &V3_1,
expect: &version.V3_1,
},
{
name: "Setting a DowngradeInfoSetRequest implies v3.5",
input: &etcdserverpb.InternalRaftRequest{DowngradeInfoSet: &membershippb.DowngradeInfoSetRequest{}},
expect: &V3_5,
expect: &version.V3_5,
},
{
name: "Enum CompareResult set to EQUAL implies v3.0",
input: &etcdserverpb.Compare{Result: etcdserverpb.Compare_EQUAL},
expect: &V3_0,
expect: &version.V3_0,
},
{
name: "Enum CompareResult set to NOT_EQUAL implies v3.1",
input: &etcdserverpb.Compare{Result: etcdserverpb.Compare_NOT_EQUAL},
expect: &V3_1,
expect: &version.V3_1,
},
{
name: "Oneof Compare version set implies v3.1",
input: &etcdserverpb.Compare{TargetUnion: &etcdserverpb.Compare_Version{}},
expect: &V3_0,
expect: &version.V3_0,
},
{
name: "Oneof Compare lease set implies v3.3",
input: &etcdserverpb.Compare{TargetUnion: &etcdserverpb.Compare_Lease{}},
expect: &V3_3,
expect: &version.V3_3,
},
}
for _, tc := range tcs {
@ -195,55 +187,55 @@ func TestEtcdVersionFromFieldOptionsString(t *testing.T) {
},
{
input: `[versionpb.etcd_version_msg]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.etcd_version_enum]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.etcd_version_field]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.etcd_version_enum_value]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `65001:0 [versionpb.etcd_version_msg]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `65004:"NodeID" [versionpb.etcd_version_msg]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `65004:"NodeID" [versionpb.etcd_version_enum]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.other_field]:"NodeID" [versionpb.etcd_version_msg]:"3.5"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.etcd_version_msg]:"3.5" 65001:0`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.etcd_version_msg]:"3.5" 65004:"NodeID"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.etcd_version_msg]:"3.5" [versionpb.other_field]:"NodeID"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `[versionpb.other_field]:"NodeID" [versionpb.etcd_version_msg]:"3.5" [versionpb.another_field]:"NodeID"`,
expect: &V3_5,
expect: &version.V3_5,
},
{
input: `65001:0 [versionpb.etcd_version_msg]:"3.5" 65001:0"`,
expect: &V3_5,
expect: &version.V3_5,
},
}
for _, tc := range tcs {
@ -265,24 +257,24 @@ func TestMaxVersion(t *testing.T) {
expect: nil,
},
{
a: &V3_5,
a: &version.V3_5,
b: nil,
expect: &V3_5,
expect: &version.V3_5,
},
{
a: nil,
b: &V3_5,
expect: &V3_5,
b: &version.V3_5,
expect: &version.V3_5,
},
{
a: &V3_6,
b: &V3_5,
expect: &V3_6,
a: &version.V3_6,
b: &version.V3_5,
expect: &version.V3_6,
},
{
a: &V3_5,
b: &V3_6,
expect: &V3_6,
a: &version.V3_5,
b: &version.V3_6,
expect: &version.V3_6,
},
}
for _, tc := range tcs {

View File

@ -22,6 +22,7 @@ import (
"github.com/coreos/go-semver/semver"
"github.com/stretchr/testify/assert"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/client/pkg/v3/fileutil"
"go.etcd.io/etcd/server/v3/storage/backend"
"go.etcd.io/etcd/server/v3/storage/schema"
@ -45,25 +46,25 @@ func TestEtctlutlMigrate(t *testing.T) {
name: "Invalid target version string",
targetVersion: "abc",
expectLogsSubString: `Error: wrong target version format, expected "X.Y", got "abc"`,
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Invalid target version",
targetVersion: "3.a",
expectLogsSubString: `Error: failed to parse target version: strconv.ParseInt: parsing "a": invalid syntax`,
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Target with only major version is invalid",
targetVersion: "3",
expectLogsSubString: `Error: wrong target version format, expected "X.Y", got "3"`,
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Target with patch version is invalid",
targetVersion: "3.6.0",
expectLogsSubString: `Error: wrong target version format, expected "X.Y", got "3.6.0"`,
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Migrate v3.5 to v3.5 is no-op",
@ -75,19 +76,19 @@ func TestEtctlutlMigrate(t *testing.T) {
name: "Upgrade v3.5 to v3.6 should work",
binary: lastReleaseBinary,
targetVersion: "3.6",
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Migrate v3.6 to v3.6 is no-op",
targetVersion: "3.6",
expectLogsSubString: "storage version up-to-date\t" + `{"storage-version": "3.6"}`,
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Downgrade v3.6 to v3.5 should fail until it's implemented",
targetVersion: "3.5",
expectLogsSubString: "cannot downgrade storage, WAL contains newer entries",
expectStorageVersion: &schema.V3_6,
expectStorageVersion: &version.V3_6,
},
{
name: "Downgrade v3.6 to v3.5 with force should work",