Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport #14368 to v3.5 #16270

Merged
merged 1 commit into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/v3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,15 +502,15 @@ func (c *Client) checkVersion() (err error) {
return
}
}
if maj < 3 || (maj == 3 && min < 2) {
if maj < 3 || (maj == 3 && min < 4) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid hard code the version in source code. For stable releases (e.g. 3.5 and 3.4), it's fine. For the main branch, let's raise a ticket to programmatically get the supported versions.

Note we only support two releases, which are 3.5 and 3.4 for now. FYI. https://etcd.io/docs/v3.5/op-guide/versioning/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I interpret is as we support the current version and one previous version only?
i.e. for v3.6, v3.5 is valid, and for v3.7, v3.6 is still valid, while 3.5 will be out of date.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I interpret is as we support the current version and one previous version only?

YES. Currently we support 3.4 and 3.5. When 3.6.0 is formally released, then 3.4 will be out of support. When 3.7.0 is released, then 3.5 will be out of support.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raised #16273

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx

rerr = ErrOldCluster
}
errc <- rerr
}(ep)
}
// wait for success
for range eps {
if err = <-errc; err == nil {
if err = <-errc; err != nil {
break
}
}
Expand Down
98 changes: 98 additions & 0 deletions client/v3/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package clientv3
import (
"context"
"fmt"
"io"
"net"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -294,3 +296,99 @@ func (mc *mockCluster) MemberUpdate(ctx context.Context, id uint64, peerAddrs []
func (mc *mockCluster) MemberPromote(ctx context.Context, id uint64) (*MemberPromoteResponse, error) {
return nil, nil
}

func TestClientRejectOldCluster(t *testing.T) {
testutil.RegisterLeakDetection(t)
var tests = []struct {
name string
endpoints []string
versions []string
expectedError error
}{
{
name: "all new versions with the same value",
endpoints: []string{"192.168.3.41:22379", "192.168.3.41:22479", "192.168.3.41:22579"},
versions: []string{"3.5.4", "3.5.4", "3.5.4"},
expectedError: nil,
},
{
name: "all new versions with different values",
endpoints: []string{"192.168.3.41:22379", "192.168.3.41:22479", "192.168.3.41:22579"},
versions: []string{"3.5.4", "3.5.4", "3.4.0"},
expectedError: nil,
},
{
name: "all old versions with different values",
endpoints: []string{"192.168.3.41:22379", "192.168.3.41:22479", "192.168.3.41:22579"},
versions: []string{"3.3.0", "3.3.0", "3.4.0"},
expectedError: ErrOldCluster,
},
{
name: "all old versions with the same value",
endpoints: []string{"192.168.3.41:22379", "192.168.3.41:22479", "192.168.3.41:22579"},
versions: []string{"3.3.0", "3.3.0", "3.3.0"},
expectedError: ErrOldCluster,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if len(tt.endpoints) != len(tt.versions) || len(tt.endpoints) == 0 {
t.Errorf("Unexpected endpoints and versions length, len(endpoints):%d, len(versions):%d", len(tt.endpoints), len(tt.versions))
return
}
endpointToVersion := make(map[string]string)
for j := range tt.endpoints {
endpointToVersion[tt.endpoints[j]] = tt.versions[j]
}
c := &Client{
ctx: context.Background(),
cfg: Config{
Endpoints: tt.endpoints,
},
mu: new(sync.RWMutex),
Maintenance: &mockMaintenance{
Version: endpointToVersion,
},
}

if err := c.checkVersion(); err != tt.expectedError {
t.Errorf("heckVersion err:%v", err)
}
})

}

}

type mockMaintenance struct {
Version map[string]string
}

func (mm mockMaintenance) Status(ctx context.Context, endpoint string) (*StatusResponse, error) {
return &StatusResponse{Version: mm.Version[endpoint]}, nil
}

func (mm mockMaintenance) AlarmList(ctx context.Context) (*AlarmResponse, error) {
return nil, nil
}

func (mm mockMaintenance) AlarmDisarm(ctx context.Context, m *AlarmMember) (*AlarmResponse, error) {
return nil, nil
}

func (mm mockMaintenance) Defragment(ctx context.Context, endpoint string) (*DefragmentResponse, error) {
return nil, nil
}

func (mm mockMaintenance) HashKV(ctx context.Context, endpoint string, rev int64) (*HashKVResponse, error) {
return nil, nil
}

func (mm mockMaintenance) Snapshot(ctx context.Context) (io.ReadCloser, error) {
return nil, nil
}

func (mm mockMaintenance) MoveLeader(ctx context.Context, transfereeID uint64) (*MoveLeaderResponse, error) {
return nil, nil
}