From d56d41b9564e36ecd1797a12412c6453de6ceb5d Mon Sep 17 00:00:00 2001 From: Matt Rickard Date: Wed, 19 Jul 2017 14:16:33 -0700 Subject: [PATCH] Add duration as a configurable type for localkube --- pkg/util/config.go | 114 ++++++++++++++++++++++++++-------------- pkg/util/config_test.go | 4 ++ 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/pkg/util/config.go b/pkg/util/config.go index 74c098eb9d62..141ec7569308 100644 --- a/pkg/util/config.go +++ b/pkg/util/config.go @@ -22,6 +22,7 @@ import ( "reflect" "strconv" "strings" + "time" utilnet "k8s.io/apimachinery/pkg/util/net" ) @@ -47,54 +48,91 @@ func findNestedElement(s string, c interface{}) (reflect.Value, error) { // setElement sets the supplied element to the value in the supplied string. The string will be coerced to the correct type. func setElement(e reflect.Value, v string) error { - switch e.Kind() { - case reflect.Int, reflect.Int32, reflect.Int64: - i, err := strconv.Atoi(v) + switch e.Interface().(type) { + case int, int32, int64: + return convertInt(e, v) + case string: + return convertString(e, v) + case float32, float64: + return convertFloat(e, v) + case bool: + return convertBool(e, v) + case net.IP: + ip := net.ParseIP(v) + if ip == nil { + return fmt.Errorf("Error converting input %s to an IP.", v) + } + e.Set(reflect.ValueOf(ip)) + case net.IPNet: + _, cidr, err := net.ParseCIDR(v) if err != nil { - return fmt.Errorf("Error converting input %s to an integer: %s", v, err) + return fmt.Errorf("Error converting input %s to a CIDR: %s", v, err) } - e.SetInt(int64(i)) - case reflect.String: - e.SetString(v) - case reflect.Float32, reflect.Float64: - f, err := strconv.ParseFloat(v, 64) + e.Set(reflect.ValueOf(*cidr)) + case utilnet.PortRange: + pr, err := utilnet.ParsePortRange(v) if err != nil { - return fmt.Errorf("Error converting input %s to a float: %s", v, err) + return fmt.Errorf("Error converting input %s to PortRange: %s", v, err) } - e.SetFloat(f) - case reflect.Bool: - b, err := strconv.ParseBool(v) + e.Set(reflect.ValueOf(*pr)) + case time.Duration: + dur, err := time.ParseDuration(v) if err != nil { - return fmt.Errorf("Error converting input %s to a bool: %s", v, err) + return fmt.Errorf("Error converting input %s to Duration: %s", v, err) } - e.SetBool(b) + e.Set(reflect.ValueOf(dur)) + case []string: + vals := strings.Split(v, ",") + e.Set(reflect.ValueOf(vals)) default: - switch t := e.Interface().(type) { - case net.IP: - ip := net.ParseIP(v) - if ip == nil { - return fmt.Errorf("Error converting input %s to an IP.", v) - } - e.Set(reflect.ValueOf(ip)) - case net.IPNet: - _, cidr, err := net.ParseCIDR(v) - if err != nil { - return fmt.Errorf("Error converting input %s to a CIDR: %s", v, err) - } - e.Set(reflect.ValueOf(*cidr)) - case utilnet.PortRange: - pr, err := utilnet.ParsePortRange(v) - if err != nil { - return fmt.Errorf("Error converting input %s to PortRange: %s", v, err) - } - e.Set(reflect.ValueOf(*pr)) - case []string: - vals := strings.Split(v, ",") - e.Set(reflect.ValueOf(vals)) + // Last ditch attempt to convert anything based on its underlying kind. + // This covers any types that are aliased to a native type + switch e.Kind() { + case reflect.Int, reflect.Int32, reflect.Int64: + return convertInt(e, v) + case reflect.String: + return convertString(e, v) + case reflect.Float32, reflect.Float64: + return convertFloat(e, v) + case reflect.Bool: + return convertBool(e, v) default: - return fmt.Errorf("Unable to set type %T.", t) + return fmt.Errorf("Unable to set type %T.", e.Kind()) } } + + return nil +} + +func convertInt(e reflect.Value, v string) error { + i, err := strconv.Atoi(v) + if err != nil { + return fmt.Errorf("Error converting input %s to an integer: %s", v, err) + } + e.SetInt(int64(i)) + return nil +} + +func convertString(e reflect.Value, v string) error { + e.SetString(v) + return nil +} + +func convertFloat(e reflect.Value, v string) error { + f, err := strconv.ParseFloat(v, 64) + if err != nil { + return fmt.Errorf("Error converting input %s to a float: %s", v, err) + } + e.SetFloat(f) + return nil +} + +func convertBool(e reflect.Value, v string) error { + b, err := strconv.ParseBool(v) + if err != nil { + return fmt.Errorf("Error converting input %s to a bool: %s", v, err) + } + e.SetBool(b) return nil } diff --git a/pkg/util/config_test.go b/pkg/util/config_test.go index 7a62b00cb30a..743f2abc2a13 100644 --- a/pkg/util/config_test.go +++ b/pkg/util/config_test.go @@ -21,6 +21,7 @@ import ( "net" "reflect" "testing" + "time" utilnet "k8s.io/apimachinery/pkg/util/net" ) @@ -58,6 +59,7 @@ type subConfig3 struct { S []string T aliasedString U net.IPNet + V time.Duration } func buildConfig() testConfig { @@ -78,6 +80,7 @@ func buildConfig() testConfig { Q: net.ParseIP("12.34.56.78"), R: utilnet.PortRange{Base: 2, Size: 4}, U: *cidr, + V: 5 * time.Second, }, }, E: &subConfig2{ @@ -180,6 +183,7 @@ func TestSetElement(t *testing.T) { {"D.I.S", "a,b", func(t testConfig) bool { return reflect.DeepEqual(t.D.I.S, []string{"a", "b"}) }}, {"D.I.T", "foo", func(t testConfig) bool { return t.D.I.T == "foo" }}, {"D.I.U", "11.22.0.0/16", func(t testConfig) bool { return t.D.I.U.String() == "11.22.0.0/16" }}, + {"D.I.V", "5s", func(t testConfig) bool { return t.D.I.V == 5*time.Second }}, } { a := buildConfig() if err := FindAndSet(tc.path, &a, tc.newval); err != nil {