Browse Source

Merge pull request #6650 from gyuho/flag

*: tests, README on environment variables in etcdctl v3
Gyu-Ho Lee 9 years ago
parent
commit
45588c1f9f
4 changed files with 55 additions and 9 deletions
  1. 3 0
      e2e/ctl_v3_kv_test.go
  2. 36 5
      e2e/ctl_v3_test.go
  3. 11 0
      etcdctl/README.md
  4. 5 4
      pkg/flags/flag.go

+ 3 - 0
e2e/ctl_v3_kv_test.go

@@ -25,6 +25,9 @@ func TestCtlV3PutClientTLS(t *testing.T)     { testCtl(t, putTest, withCfg(confi
 func TestCtlV3PutClientAutoTLS(t *testing.T) { testCtl(t, putTest, withCfg(configClientAutoTLS)) }
 func TestCtlV3PutPeerTLS(t *testing.T)       { testCtl(t, putTest, withCfg(configPeerTLS)) }
 func TestCtlV3PutTimeout(t *testing.T)       { testCtl(t, putTest, withDialTimeout(0)) }
+func TestCtlV3PutClientTLSFlagByEnv(t *testing.T) {
+	testCtl(t, putTest, withCfg(configClientTLS), withFlagByEnv())
+}
 
 func TestCtlV3Get(t *testing.T)              { testCtl(t, getTest) }
 func TestCtlV3GetNoTLS(t *testing.T)         { testCtl(t, getTest, withCfg(configNoTLS)) }

+ 36 - 5
e2e/ctl_v3_test.go

@@ -15,11 +15,13 @@
 package e2e
 
 import (
+	"fmt"
 	"os"
 	"strings"
 	"testing"
 	"time"
 
+	"github.com/coreos/etcd/pkg/flags"
 	"github.com/coreos/etcd/pkg/testutil"
 	"github.com/coreos/etcd/version"
 )
@@ -57,6 +59,8 @@ type ctlCtx struct {
 
 	epc *etcdProcessCluster
 
+	envMap map[string]struct{}
+
 	dialTimeout time.Duration
 
 	quorum      bool // if true, set up 3-node cluster and linearizable read
@@ -105,6 +109,10 @@ func withNoStrictReconfig() ctlOption {
 	return func(cx *ctlCtx) { cx.noStrictReconfig = true }
 }
 
+func withFlagByEnv() ctlOption {
+	return func(cx *ctlCtx) { cx.envMap = make(map[string]struct{}) }
+}
+
 func testCtl(t *testing.T, testFunc func(ctlCtx), opts ...ctlOption) {
 	defer testutil.AfterTest(t)
 
@@ -133,6 +141,11 @@ func testCtl(t *testing.T, testFunc func(ctlCtx), opts ...ctlOption) {
 
 	defer func() {
 		os.Unsetenv("ETCDCTL_API")
+		if ret.envMap != nil {
+			for k := range ret.envMap {
+				os.Unsetenv(k)
+			}
+		}
 		if errC := ret.epc.Close(); errC != nil {
 			t.Fatalf("error closing etcd processes (%v)", errC)
 		}
@@ -160,22 +173,40 @@ func (cx *ctlCtx) prefixArgs(eps []string) []string {
 		panic("v3 proxy not implemented")
 	}
 
-	cmdArgs := []string{ctlBinPath, "--endpoints", strings.Join(eps, ","), "--dial-timeout", cx.dialTimeout.String()}
+	fmap := make(map[string]string)
+	fmap["endpoints"] = strings.Join(eps, ",")
+	fmap["dial-timeout"] = cx.dialTimeout.String()
 	if cx.epc.cfg.clientTLS == clientTLS {
 		if cx.epc.cfg.isClientAutoTLS {
-			cmdArgs = append(cmdArgs, "--insecure-transport=false", "--insecure-skip-tls-verify")
+			fmap["insecure-transport"] = "false"
+			fmap["insecure-skip-tls-verify"] = "true"
 		} else {
-			cmdArgs = append(cmdArgs, "--cacert", caPath, "--cert", certPath, "--key", privateKeyPath)
+			fmap["cacert"] = caPath
+			fmap["cert"] = certPath
+			fmap["key"] = privateKeyPath
 		}
 	}
-
 	if cx.user != "" {
-		cmdArgs = append(cmdArgs, "--user="+cx.user+":"+cx.pass)
+		fmap["user"] = cx.user + ":" + cx.pass
 	}
 
+	useEnv := cx.envMap != nil
+
+	cmdArgs := []string{ctlBinPath}
+	for k, v := range fmap {
+		if useEnv {
+			ek := flags.FlagToEnv("ETCDCTL", k)
+			os.Setenv(ek, v)
+			cx.envMap[ek] = struct{}{}
+		} else {
+			cmdArgs = append(cmdArgs, fmt.Sprintf("--%s=%s", k, v))
+		}
+	}
 	return cmdArgs
 }
 
+// PrefixArgs prefixes etcdctl command.
+// Make sure to unset environment variables after tests.
 func (cx *ctlCtx) PrefixArgs() []string {
 	return cx.prefixArgs(cx.epc.grpcEndpoints())
 }

+ 11 - 0
etcdctl/README.md

@@ -4,6 +4,17 @@ etcdctl
 `etcdctl` is a command line client for [etcd][etcd].
 Make sure to set environment variable `ETCDCTL_API=3`. For etcdctl v2, please check [READMEv2][READMEv2].
 
+Global flags (e.g., `dial-timeout`, `--cacert`, `--cert`, `--key`) can be set with environment variables:
+
+```
+ETCDCTL_DIAL_TIMEOUT=3s
+ETCDCTL_CACERT=/tmp/ca.pem
+ETCDCTL_CERT=/tmp/cert.pem
+ETCDCTL_KEY=/tmp/key.pem
+```
+
+Prefix flag strings with `ETCDCTL_`, convert all letters to upper-case, and replace dash(`-`) with underscore(`_`).
+
 ## Commands
 
 ### VERSION

+ 5 - 4
pkg/flags/flag.go

@@ -74,7 +74,7 @@ func SetFlagsFromEnv(prefix string, fs *flag.FlagSet) error {
 	var err error
 	alreadySet := make(map[string]bool)
 	fs.Visit(func(f *flag.Flag) {
-		alreadySet[flagToEnv(prefix, f.Name)] = true
+		alreadySet[FlagToEnv(prefix, f.Name)] = true
 	})
 	usedEnvKey := make(map[string]bool)
 	fs.VisitAll(func(f *flag.Flag) {
@@ -94,7 +94,7 @@ func SetPflagsFromEnv(prefix string, fs *pflag.FlagSet) error {
 	usedEnvKey := make(map[string]bool)
 	fs.VisitAll(func(f *pflag.Flag) {
 		if f.Changed {
-			alreadySet[flagToEnv(prefix, f.Name)] = true
+			alreadySet[FlagToEnv(prefix, f.Name)] = true
 		}
 		if serr := setFlagFromEnv(fs, prefix, f.Name, usedEnvKey, alreadySet, false); serr != nil {
 			err = serr
@@ -103,7 +103,8 @@ func SetPflagsFromEnv(prefix string, fs *pflag.FlagSet) error {
 	return err
 }
 
-func flagToEnv(prefix, name string) string {
+// FlagToEnv converts flag string to upper-case environment variable key string.
+func FlagToEnv(prefix, name string) string {
 	return prefix + "_" + strings.ToUpper(strings.Replace(name, "-", "_", -1))
 }
 
@@ -131,7 +132,7 @@ type flagSetter interface {
 }
 
 func setFlagFromEnv(fs flagSetter, prefix, fname string, usedEnvKey, alreadySet map[string]bool, log bool) error {
-	key := flagToEnv(prefix, fname)
+	key := FlagToEnv(prefix, fname)
 	if !alreadySet[key] {
 		val := os.Getenv(key)
 		if val != "" {