From dddb0ac6a591a02a77c94164ae0db17dc5b2e5a1 Mon Sep 17 00:00:00 2001 From: Thomas Jungblut Date: Wed, 3 Aug 2022 18:27:26 +0200 Subject: [PATCH] UPSTREAM : etcdctl: allow move-leader to connect to multiple endpoints Re-opening closed PR etcd-io#11775 which was originaly authored by benmoss. Then again opened PR etcd-io#12757 which was authored by zerodayz. The mustClientForCmd function is responsible for parsing environment variables and flags into configuration data. A change was made in etcd-io#9382 to call Fatal if a flag is provided multiple times. This means that we cannot call the mustClientForCmd function more than once, since it will think that flags parsed the first time are now being redefined and error out. Some people have commented about this in etcd-io#8380 but I don't think there's an open issue for it. Signed-off-by: Thomas Jungblut --- etcdctl/ctlv3/command/move_leader_command.go | 5 +-- tests/e2e/ctl_v3_move_leader_test.go | 33 ++++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/etcdctl/ctlv3/command/move_leader_command.go b/etcdctl/ctlv3/command/move_leader_command.go index 098c897cd7a9..4e0b237e66f8 100644 --- a/etcdctl/ctlv3/command/move_leader_command.go +++ b/etcdctl/ctlv3/command/move_leader_command.go @@ -19,6 +19,7 @@ import ( "strconv" "github.com/spf13/cobra" + "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/pkg/v3/cobrautl" ) @@ -43,7 +44,8 @@ func transferLeadershipCommandFunc(cmd *cobra.Command, args []string) { cobrautl.ExitWithError(cobrautl.ExitBadArgs, err) } - c := mustClientFromCmd(cmd) + cfg := clientConfigFromCmd(cmd) + c := cfg.mustClient() eps := c.Endpoints() c.Close() @@ -53,7 +55,6 @@ func transferLeadershipCommandFunc(cmd *cobra.Command, args []string) { var leaderCli *clientv3.Client var leaderID uint64 for _, ep := range eps { - cfg := clientConfigFromCmd(cmd) cfg.endpoints = []string{ep} cli := cfg.mustClient() resp, serr := cli.Status(ctx, ep) diff --git a/tests/e2e/ctl_v3_move_leader_test.go b/tests/e2e/ctl_v3_move_leader_test.go index 05dc49939992..70bc50ac445b 100644 --- a/tests/e2e/ctl_v3_move_leader_test.go +++ b/tests/e2e/ctl_v3_move_leader_test.go @@ -27,15 +27,31 @@ import ( "go.etcd.io/etcd/client/v3" ) -func TestCtlV3MoveLeaderSecure(t *testing.T) { - testCtlV3MoveLeader(t, *newConfigTLS()) -} +func TestCtlV3MoveLeaderScenarios(t *testing.T) { + securityParent := map[string]struct { + cfg etcdProcessClusterConfig + }{ + "Secure": {cfg: *newConfigTLS()}, + "Insecure": {cfg: *newConfigNoTLS()}, + } -func TestCtlV3MoveLeaderInsecure(t *testing.T) { - testCtlV3MoveLeader(t, *newConfigNoTLS()) + tests := map[string]struct { + env map[string]string + }{ + "happy path": {env: map[string]string{}}, + "with env": {env: map[string]string{"ETCDCTL_ENDPOINTS": "something-else-is-set"}}, + } + + for testName, tc := range securityParent { + for subTestName, tx := range tests { + t.Run(testName+" "+subTestName, func(t *testing.T) { + testCtlV3MoveLeader(t, tc.cfg, tx.env) + }) + } + } } -func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig) { +func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig, envVars map[string]string) { BeforeTest(t) epc := setupEtcdctlTest(t, &cfg, true) @@ -94,6 +110,7 @@ func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig) { cfg: *newConfigNoTLS(), dialTimeout: 7 * time.Second, epc: epc, + envMap: envVars, } tests := []struct { @@ -108,6 +125,10 @@ func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig) { []string{cx.epc.EndpointsV3()[leadIdx]}, fmt.Sprintf("Leadership transferred from %s to %s", types.ID(leaderID), types.ID(transferee)), }, + { // request to all endpoints + cx.epc.EndpointsV3(), + fmt.Sprintf("Leadership transferred"), + }, } for i, tc := range tests { prefix := cx.prefixArgs(tc.eps)