1// Copyright 2017 The etcd Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package e2e 16 17import ( 18 "context" 19 "crypto/tls" 20 "fmt" 21 "os" 22 "testing" 23 "time" 24 25 "go.etcd.io/etcd/clientv3" 26 "go.etcd.io/etcd/pkg/testutil" 27 "go.etcd.io/etcd/pkg/transport" 28 "go.etcd.io/etcd/pkg/types" 29) 30 31func TestCtlV3MoveLeaderSecure(t *testing.T) { 32 testCtlV3MoveLeader(t, configTLS) 33} 34 35func TestCtlV3MoveLeaderInsecure(t *testing.T) { 36 testCtlV3MoveLeader(t, configNoTLS) 37} 38 39func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig) { 40 defer testutil.AfterTest(t) 41 42 epc := setupEtcdctlTest(t, &cfg, true) 43 defer func() { 44 if errC := epc.Close(); errC != nil { 45 t.Fatalf("error closing etcd processes (%v)", errC) 46 } 47 }() 48 49 var tcfg *tls.Config 50 if cfg.clientTLS == clientTLS { 51 tinfo := transport.TLSInfo{ 52 CertFile: certPath, 53 KeyFile: privateKeyPath, 54 TrustedCAFile: caPath, 55 } 56 var err error 57 tcfg, err = tinfo.ClientConfig() 58 if err != nil { 59 t.Fatal(err) 60 } 61 } 62 63 var leadIdx int 64 var leaderID uint64 65 var transferee uint64 66 for i, ep := range epc.EndpointsV3() { 67 cli, err := clientv3.New(clientv3.Config{ 68 Endpoints: []string{ep}, 69 DialTimeout: 3 * time.Second, 70 TLS: tcfg, 71 }) 72 if err != nil { 73 t.Fatal(err) 74 } 75 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 76 resp, err := cli.Status(ctx, ep) 77 if err != nil { 78 t.Fatalf("failed to get status from endpoint %s: %v", ep, err) 79 } 80 cancel() 81 cli.Close() 82 83 if resp.Header.GetMemberId() == resp.Leader { 84 leadIdx = i 85 leaderID = resp.Leader 86 } else { 87 transferee = resp.Header.GetMemberId() 88 } 89 } 90 91 os.Setenv("ETCDCTL_API", "3") 92 defer os.Unsetenv("ETCDCTL_API") 93 cx := ctlCtx{ 94 t: t, 95 cfg: configNoTLS, 96 dialTimeout: 7 * time.Second, 97 epc: epc, 98 } 99 100 tests := []struct { 101 prefixes []string 102 expect string 103 }{ 104 { // request to non-leader 105 cx.prefixArgs([]string{cx.epc.EndpointsV3()[(leadIdx+1)%3]}), 106 "no leader endpoint given at ", 107 }, 108 { // request to leader 109 cx.prefixArgs([]string{cx.epc.EndpointsV3()[leadIdx]}), 110 fmt.Sprintf("Leadership transferred from %s to %s", types.ID(leaderID), types.ID(transferee)), 111 }, 112 } 113 for i, tc := range tests { 114 cmdArgs := append(tc.prefixes, "move-leader", types.ID(transferee).String()) 115 if err := spawnWithExpect(cmdArgs, tc.expect); err != nil { 116 t.Fatalf("#%d: %v", i, err) 117 } 118 } 119} 120