diff --git a/etcdmain/config.go b/etcdmain/config.go index 4c5cdc90c..afa54d9cd 100644 --- a/etcdmain/config.go +++ b/etcdmain/config.go @@ -133,7 +133,7 @@ func newConfig() *config { fs.StringVar(&cfg.ec.WalDir, "wal-dir", cfg.ec.WalDir, "Path to the dedicated wal directory.") fs.Var(flags.NewURLsValue(embed.DefaultListenPeerURLs), "listen-peer-urls", "List of URLs to listen on for peer traffic.") fs.Var(flags.NewURLsValue(embed.DefaultListenClientURLs), "listen-client-urls", "List of URLs to listen on for client traffic.") - fs.StringVar(&cfg.ec.ListenMetricsUrlsJSON, "listen-metrics-urls", "", "List of URLs to listen on for metrics.") + fs.Var(flags.NewURLsValue(""), "listen-metrics-urls", "List of URLs to listen on for metrics.") fs.UintVar(&cfg.ec.MaxSnapFiles, "max-snapshots", cfg.ec.MaxSnapFiles, "Maximum number of snapshot files to retain (0 is unlimited).") fs.UintVar(&cfg.ec.MaxWalFiles, "max-wals", cfg.ec.MaxWalFiles, "Maximum number of wal files to retain (0 is unlimited).") fs.StringVar(&cfg.ec.Name, "name", cfg.ec.Name, "Human-readable name for this member.") @@ -269,14 +269,7 @@ func (cfg *config) configFromCmdLine() error { cfg.ec.LCUrls = flags.URLsFromFlag(cfg.cf.flagSet, "listen-client-urls") cfg.ec.ACUrls = flags.URLsFromFlag(cfg.cf.flagSet, "advertise-client-urls") cfg.ec.HostWhitelist = flags.StringSliceFromFlag(cfg.cf.flagSet, "host-whitelist") - - if len(cfg.ec.ListenMetricsUrlsJSON) > 0 { - u, err := types.NewURLs(strings.Split(cfg.ec.ListenMetricsUrlsJSON, ",")) - if err != nil { - plog.Fatalf("unexpected error setting up listen-metrics-urls: %v", err) - } - cfg.ec.ListenMetricsUrls = []url.URL(u) - } + cfg.ec.ListenMetricsUrls = flags.URLsFromFlag(cfg.cf.flagSet, "listen-metrics-urls") cfg.ec.ClusterState = cfg.cf.clusterState.String() cfg.cp.Fallback = cfg.cf.fallback.String() @@ -311,12 +304,22 @@ func (cfg *config) configFromFile(path string) error { if yerr := yaml.Unmarshal(b, &cfg.cp); yerr != nil { return yerr } + + if cfg.ec.ListenMetricsUrlsJSON != "" { + us, err := types.NewURLs(strings.Split(cfg.ec.ListenMetricsUrlsJSON, ",")) + if err != nil { + plog.Panicf("unexpected error setting up listen-metrics-urls: %v", err) + } + cfg.ec.ListenMetricsUrls = []url.URL(us) + } + if cfg.cp.FallbackJSON != "" { if err := cfg.cf.fallback.Set(cfg.cp.FallbackJSON); err != nil { plog.Panicf("unexpected error setting up discovery-fallback flag: %v", err) } cfg.cp.Fallback = cfg.cf.fallback.String() } + if cfg.cp.ProxyJSON != "" { if err := cfg.cf.proxy.Set(cfg.cp.ProxyJSON); err != nil { plog.Panicf("unexpected error setting up proxyFlag: %v", err) diff --git a/pkg/flags/urls.go b/pkg/flags/urls.go index 6383d7e92..9d2818774 100644 --- a/pkg/flags/urls.go +++ b/pkg/flags/urls.go @@ -20,18 +20,17 @@ import ( "github.com/coreos/etcd/pkg/types" ) +// URLsValue wraps "types.URLs". type URLsValue types.URLs // Set parses a command line set of URLs formatted like: // http://127.0.0.1:2380,http://10.1.1.2:80 func (us *URLsValue) Set(s string) error { - strs := strings.Split(s, ",") - nus, err := types.NewURLs(strs) + ss, err := types.NewURLs(strings.Split(s, ",")) if err != nil { return err } - - *us = URLsValue(nus) + *us = URLsValue(ss) return nil } @@ -43,9 +42,14 @@ func (us *URLsValue) String() string { return strings.Join(all, ",") } -func NewURLsValue(init string) *URLsValue { +// NewURLsValue implements "url.URL" slice as flag.Value interface. +// Given value is to be separated by comma. +func NewURLsValue(s string) *URLsValue { + if s == "" { + return &URLsValue{} + } v := &URLsValue{} - if err := v.Set(init); err != nil { + if err := v.Set(s); err != nil { plog.Panicf("new URLsValue should never fail: %v", err) } return v diff --git a/pkg/flags/urls_test.go b/pkg/flags/urls_test.go index bcccdfaaa..ff4bda8d4 100644 --- a/pkg/flags/urls_test.go +++ b/pkg/flags/urls_test.go @@ -15,6 +15,8 @@ package flags import ( + "net/url" + "reflect" "testing" ) @@ -45,17 +47,27 @@ func TestValidateURLsValueBad(t *testing.T) { } } -func TestValidateURLsValueGood(t *testing.T) { - tests := []string{ - "https://1.2.3.4:8080", - "http://10.1.1.1:80", - "http://localhost:80", - "http://:80", +func TestNewURLsValue(t *testing.T) { + tests := []struct { + s string + exp []url.URL + }{ + {s: "https://1.2.3.4:8080", exp: []url.URL{{Scheme: "https", Host: "1.2.3.4:8080"}}}, + {s: "http://10.1.1.1:80", exp: []url.URL{{Scheme: "http", Host: "10.1.1.1:80"}}}, + {s: "http://localhost:80", exp: []url.URL{{Scheme: "http", Host: "localhost:80"}}}, + {s: "http://:80", exp: []url.URL{{Scheme: "http", Host: ":80"}}}, + { + s: "http://localhost:1,https://localhost:2", + exp: []url.URL{ + {Scheme: "http", Host: "localhost:1"}, + {Scheme: "https", Host: "localhost:2"}, + }, + }, } - for i, in := range tests { - u := URLsValue{} - if err := u.Set(in); err != nil { - t.Errorf("#%d: err=%v, want nil for in=%q", i, err, in) + for i := range tests { + uu := []url.URL(*NewURLsValue(tests[i].s)) + if !reflect.DeepEqual(tests[i].exp, uu) { + t.Fatalf("#%d: expected %+v, got %+v", i, tests[i].exp, uu) } } }