From 6e37a72295e41b5311c6e3884e91314f8b347226 Mon Sep 17 00:00:00 2001 From: Robin Cernin Date: Wed, 10 Mar 2021 08:43:52 +1000 Subject: [PATCH] etcdctl: allow move-leader to connect to multiple endpoints with TLS Re-opening closed PR #11775 which was originaly authored by benmoss. The mustClientForCmd function is responsible for parsing environment variables and flags into configuration data. A change was made in #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 #8380 but I don't think there's an open issue for it. --- etcdctl/ctlv3/command/move_leader_command.go | 4 +-- tests/e2e/ctl_v3_move_leader_test.go | 34 ++++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/etcdctl/ctlv3/command/move_leader_command.go b/etcdctl/ctlv3/command/move_leader_command.go index 1aee99b24445..a07e095b5e1a 100644 --- a/etcdctl/ctlv3/command/move_leader_command.go +++ b/etcdctl/ctlv3/command/move_leader_command.go @@ -42,7 +42,8 @@ func transferLeadershipCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitBadArgs, err) } - c := mustClientFromCmd(cmd) + cfg := clientConfigFromCmd(cmd) + c := cfg.mustClient() eps := c.Endpoints() c.Close() @@ -52,7 +53,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 507ca4c16213..8b1d6fd55b27 100644 --- a/tests/e2e/ctl_v3_move_leader_test.go +++ b/tests/e2e/ctl_v3_move_leader_test.go @@ -29,25 +29,36 @@ import ( ) func TestCtlV3MoveLeaderSecure(t *testing.T) { - testCtlV3MoveLeader(t, *newConfigTLS()) + testCtlV3MoveLeader(t, withCfg(*newConfigTLS())) + testCtlV3MoveLeader(t, withCfg(*newConfigTLS()), withFlagByEnv()) } func TestCtlV3MoveLeaderInsecure(t *testing.T) { - testCtlV3MoveLeader(t, *newConfigNoTLS()) + testCtlV3MoveLeader(t, withCfg(*newConfigNoTLS())) + testCtlV3MoveLeader(t, withCfg(*newConfigNoTLS()), withFlagByEnv()) } -func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig) { +func testCtlV3MoveLeader(t *testing.T, opts ...ctlOption) { defer testutil.AfterTest(t) - epc := setupEtcdctlTest(t, &cfg, true) + ret := ctlCtx{ + t: t, + cfg: *newConfigAutoTLS(), + dialTimeout: 7 * time.Second, + } + ret.applyOpts(opts) + + epc := setupEtcdctlTest(t, &ret.cfg, true) + ret.epc = epc + defer func() { - if errC := epc.Close(); errC != nil { + if errC := ret.epc.Close(); errC != nil { t.Fatalf("error closing etcd processes (%v)", errC) } }() var tcfg *tls.Config - if cfg.clientTLS == clientTLS { + if ret.cfg.clientTLS == clientTLS { tinfo := transport.TLSInfo{ CertFile: certPath, KeyFile: privateKeyPath, @@ -90,26 +101,21 @@ func testCtlV3MoveLeader(t *testing.T, cfg etcdProcessClusterConfig) { os.Setenv("ETCDCTL_API", "3") defer os.Unsetenv("ETCDCTL_API") - cx := ctlCtx{ - t: t, - cfg: *newConfigNoTLS(), - dialTimeout: 7 * time.Second, - epc: epc, - } tests := []struct { prefixes []string expect string }{ { // request to non-leader - cx.prefixArgs([]string{cx.epc.EndpointsV3()[(leadIdx+1)%3]}), + ret.prefixArgs([]string{ret.epc.EndpointsV3()[(leadIdx+1)%3]}), "no leader endpoint given at ", }, { // request to leader - cx.prefixArgs([]string{cx.epc.EndpointsV3()[leadIdx]}), + ret.prefixArgs([]string{ret.epc.EndpointsV3()[leadIdx]}), fmt.Sprintf("Leadership transferred from %s to %s", types.ID(leaderID), types.ID(transferee)), }, } + for i, tc := range tests { cmdArgs := append(tc.prefixes, "move-leader", types.ID(transferee).String()) if err := spawnWithExpect(cmdArgs, tc.expect); err != nil {