mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
pkg: move everything into subpackages
This commit is contained in:
137
pkg/flags/flag.go
Normal file
137
pkg/flags/flag.go
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright 2014 CoreOS, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/etcd/pkg/transport"
|
||||
)
|
||||
|
||||
// DeprecatedFlag encapsulates a flag that may have been previously valid but
|
||||
// is now deprecated. If a DeprecatedFlag is set, an error occurs.
|
||||
type DeprecatedFlag struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (f *DeprecatedFlag) Set(_ string) error {
|
||||
return fmt.Errorf(`flag "-%s" is no longer supported.`, f.Name)
|
||||
}
|
||||
|
||||
func (f *DeprecatedFlag) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// IgnoredFlag encapsulates a flag that may have been previously valid but is
|
||||
// now ignored. If an IgnoredFlag is set, a warning is printed and
|
||||
// operation continues.
|
||||
type IgnoredFlag struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// IsBoolFlag is defined to allow the flag to be defined without an argument
|
||||
func (f *IgnoredFlag) IsBoolFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *IgnoredFlag) Set(s string) error {
|
||||
log.Printf(`WARNING: flag "-%s" is no longer supported - ignoring.`, f.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *IgnoredFlag) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func UsageWithIgnoredFlagsFunc(fs *flag.FlagSet, ignore []string) func() {
|
||||
iMap := make(map[string]struct{}, len(ignore))
|
||||
for _, name := range ignore {
|
||||
iMap[name] = struct{}{}
|
||||
}
|
||||
|
||||
return func() {
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
if _, ok := iMap[f.Name]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
format := " -%s=%s: %s\n"
|
||||
fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// SetFlagsFromEnv parses all registered flags in the given flagset,
|
||||
// and if they are not already set it attempts to set their values from
|
||||
// environment variables. Environment variables take the name of the flag but
|
||||
// are UPPERCASE, have the prefix "ETCD_", and any dashes are replaced by
|
||||
// underscores - for example: some-flag => ETCD_SOME_FLAG
|
||||
func SetFlagsFromEnv(fs *flag.FlagSet) {
|
||||
alreadySet := make(map[string]bool)
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
alreadySet[f.Name] = true
|
||||
})
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
if !alreadySet[f.Name] {
|
||||
key := "ETCD_" + strings.ToUpper(strings.Replace(f.Name, "-", "_", -1))
|
||||
val := os.Getenv(key)
|
||||
if val != "" {
|
||||
fs.Set(f.Name, val)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// URLsFromFlags decides what URLs should be using two different flags
|
||||
// as datasources. The first flag's Value must be of type URLs, while
|
||||
// the second must be of type IPAddressPort. If both of these flags
|
||||
// are set, an error will be returned. If only the first flag is set,
|
||||
// the underlying url.URL objects will be returned unmodified. If the
|
||||
// second flag happens to be set, the underlying IPAddressPort will be
|
||||
// converted to a url.URL and returned. The Scheme of the returned
|
||||
// url.URL will be http unless the provided TLSInfo object is non-empty.
|
||||
// If neither of the flags have been explicitly set, the default value
|
||||
// of the first flag will be returned unmodified.
|
||||
func URLsFromFlags(fs *flag.FlagSet, urlsFlagName string, addrFlagName string, tlsInfo transport.TLSInfo) ([]url.URL, error) {
|
||||
visited := make(map[string]struct{})
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
visited[f.Name] = struct{}{}
|
||||
})
|
||||
|
||||
_, urlsFlagIsSet := visited[urlsFlagName]
|
||||
_, addrFlagIsSet := visited[addrFlagName]
|
||||
|
||||
if addrFlagIsSet {
|
||||
if urlsFlagIsSet {
|
||||
return nil, fmt.Errorf("Set only one of flags -%s and -%s", urlsFlagName, addrFlagName)
|
||||
}
|
||||
|
||||
addr := *fs.Lookup(addrFlagName).Value.(*IPAddressPort)
|
||||
addrURL := url.URL{Scheme: "http", Host: addr.String()}
|
||||
if !tlsInfo.Empty() {
|
||||
addrURL.Scheme = "https"
|
||||
}
|
||||
return []url.URL{addrURL}, nil
|
||||
}
|
||||
|
||||
return []url.URL(*fs.Lookup(urlsFlagName).Value.(*URLsValue)), nil
|
||||
}
|
||||
153
pkg/flags/flag_test.go
Normal file
153
pkg/flags/flag_test.go
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
Copyright 2014 CoreOS, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/transport"
|
||||
)
|
||||
|
||||
func TestSetFlagsFromEnv(t *testing.T) {
|
||||
fs := flag.NewFlagSet("testing", flag.ExitOnError)
|
||||
fs.String("a", "", "")
|
||||
fs.String("b", "", "")
|
||||
fs.String("c", "", "")
|
||||
fs.Parse([]string{})
|
||||
|
||||
os.Clearenv()
|
||||
// flags should be settable using env vars
|
||||
os.Setenv("ETCD_A", "foo")
|
||||
// and command-line flags
|
||||
if err := fs.Set("b", "bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// command-line flags take precedence over env vars
|
||||
os.Setenv("ETCD_C", "woof")
|
||||
if err := fs.Set("c", "quack"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// first verify that flags are as expected before reading the env
|
||||
for f, want := range map[string]string{
|
||||
"a": "",
|
||||
"b": "bar",
|
||||
"c": "quack",
|
||||
} {
|
||||
if got := fs.Lookup(f).Value.String(); got != want {
|
||||
t.Fatalf("flag %q=%q, want %q", f, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// now read the env and verify flags were updated as expected
|
||||
SetFlagsFromEnv(fs)
|
||||
for f, want := range map[string]string{
|
||||
"a": "foo",
|
||||
"b": "bar",
|
||||
"c": "quack",
|
||||
} {
|
||||
if got := fs.Lookup(f).Value.String(); got != want {
|
||||
t.Errorf("flag %q=%q, want %q", f, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsFromFlags(t *testing.T) {
|
||||
tests := []struct {
|
||||
args []string
|
||||
tlsInfo transport.TLSInfo
|
||||
wantURLs []url.URL
|
||||
wantFail bool
|
||||
}{
|
||||
// use -urls default when no flags defined
|
||||
{
|
||||
args: []string{},
|
||||
tlsInfo: transport.TLSInfo{},
|
||||
wantURLs: []url.URL{
|
||||
url.URL{Scheme: "http", Host: "127.0.0.1:2379"},
|
||||
},
|
||||
wantFail: false,
|
||||
},
|
||||
|
||||
// explicitly setting -urls should carry through
|
||||
{
|
||||
args: []string{"-urls=https://192.0.3.17:2930,http://127.0.0.1:1024"},
|
||||
tlsInfo: transport.TLSInfo{},
|
||||
wantURLs: []url.URL{
|
||||
url.URL{Scheme: "http", Host: "127.0.0.1:1024"},
|
||||
url.URL{Scheme: "https", Host: "192.0.3.17:2930"},
|
||||
},
|
||||
wantFail: false,
|
||||
},
|
||||
|
||||
// explicitly setting -addr should carry through
|
||||
{
|
||||
args: []string{"-addr=192.0.2.3:1024"},
|
||||
tlsInfo: transport.TLSInfo{},
|
||||
wantURLs: []url.URL{
|
||||
url.URL{Scheme: "http", Host: "192.0.2.3:1024"},
|
||||
},
|
||||
wantFail: false,
|
||||
},
|
||||
|
||||
// scheme prepended to -addr should be https if TLSInfo non-empty
|
||||
{
|
||||
args: []string{"-addr=192.0.2.3:1024"},
|
||||
tlsInfo: transport.TLSInfo{
|
||||
CertFile: "/tmp/foo",
|
||||
KeyFile: "/tmp/bar",
|
||||
},
|
||||
wantURLs: []url.URL{
|
||||
url.URL{Scheme: "https", Host: "192.0.2.3:1024"},
|
||||
},
|
||||
wantFail: false,
|
||||
},
|
||||
|
||||
// explicitly setting both -urls and -addr should fail
|
||||
{
|
||||
args: []string{"-urls=https://127.0.0.1:1024", "-addr=192.0.2.3:1024"},
|
||||
tlsInfo: transport.TLSInfo{},
|
||||
wantURLs: nil,
|
||||
wantFail: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
fs := flag.NewFlagSet("test", flag.PanicOnError)
|
||||
fs.Var(NewURLsValue("http://127.0.0.1:2379"), "urls", "")
|
||||
fs.Var(&IPAddressPort{}, "addr", "")
|
||||
|
||||
if err := fs.Parse(tt.args); err != nil {
|
||||
t.Errorf("#%d: failed to parse flags: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
gotURLs, err := URLsFromFlags(fs, "urls", "addr", tt.tlsInfo)
|
||||
if tt.wantFail != (err != nil) {
|
||||
t.Errorf("#%d: wantFail=%t, got err=%v", i, tt.wantFail, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.wantURLs, gotURLs) {
|
||||
t.Errorf("#%d: incorrect URLs\nwant=%#v\ngot=%#v", i, tt.wantURLs, gotURLs)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user