diff --git a/logical/framework/backend.go b/logical/framework/backend.go index b53c9f21b..042c0e70e 100644 --- a/logical/framework/backend.go +++ b/logical/framework/backend.go @@ -373,6 +373,8 @@ func (t FieldType) Zero() interface{} { return false case TypeMap: return map[string]interface{}{} + case TypeDurationSecond: + return 0 default: panic("unknown type: " + t.String()) } diff --git a/logical/framework/backend_test.go b/logical/framework/backend_test.go index 093e3e5cd..4058d194d 100644 --- a/logical/framework/backend_test.go +++ b/logical/framework/backend_test.go @@ -508,6 +508,16 @@ func TestFieldSchemaDefaultOrZero(t *testing.T) { &FieldSchema{Type: TypeString}, "", }, + + "default duration set": { + &FieldSchema{Type: TypeDurationSecond, Default: 60}, + 60, + }, + + "default duration not set": { + &FieldSchema{Type: TypeDurationSecond}, + 0, + }, } for name, tc := range cases { diff --git a/logical/framework/field_data.go b/logical/framework/field_data.go index e8255c8c5..40d1ac182 100644 --- a/logical/framework/field_data.go +++ b/logical/framework/field_data.go @@ -2,6 +2,9 @@ package framework import ( "fmt" + "strconv" + "strings" + "time" "github.com/mitchellh/mapstructure" ) @@ -64,13 +67,7 @@ func (d *FieldData) GetOkErr(k string) (interface{}, bool, error) { } switch schema.Type { - case TypeBool: - fallthrough - case TypeInt: - fallthrough - case TypeMap: - fallthrough - case TypeString: + case TypeBool, TypeInt, TypeMap, TypeDurationSecond, TypeString: return d.getPrimitive(k, schema) default: return nil, false, @@ -114,6 +111,38 @@ func (d *FieldData) getPrimitive( } return result, true, nil + + case TypeDurationSecond: + var result int + switch inp := raw.(type) { + case int: + result = inp + case float32: + result = int(inp) + case float64: + result = int(inp) + case string: + // Look for a suffix otherwise its a plain second value + if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") { + dur, err := time.ParseDuration(inp) + if err != nil { + return nil, true, err + } + result = int(dur.Seconds()) + } else { + // Plain integer + val, err := strconv.ParseInt(inp, 10, 64) + if err != nil { + return nil, true, err + } + result = int(val) + } + + default: + return nil, false, fmt.Errorf("invalid input '%v'", raw) + } + return result, true, nil + default: panic(fmt.Sprintf("Unknown type: %s", schema.Type)) } diff --git a/logical/framework/field_data_test.go b/logical/framework/field_data_test.go index 000ded72a..e6a32f8cb 100644 --- a/logical/framework/field_data_test.go +++ b/logical/framework/field_data_test.go @@ -91,6 +91,50 @@ func TestFieldDataGet(t *testing.T) { "child": true, }, }, + + "duration type, string value": { + map[string]*FieldSchema{ + "foo": &FieldSchema{Type: TypeDurationSecond}, + }, + map[string]interface{}{ + "foo": "42", + }, + "foo", + 42, + }, + + "duration type, string duration value": { + map[string]*FieldSchema{ + "foo": &FieldSchema{Type: TypeDurationSecond}, + }, + map[string]interface{}{ + "foo": "42m", + }, + "foo", + 2520, + }, + + "duration type, int value": { + map[string]*FieldSchema{ + "foo": &FieldSchema{Type: TypeDurationSecond}, + }, + map[string]interface{}{ + "foo": 42, + }, + "foo", + 42, + }, + + "duration type, float value": { + map[string]*FieldSchema{ + "foo": &FieldSchema{Type: TypeDurationSecond}, + }, + map[string]interface{}{ + "foo": 42.0, + }, + "foo", + 42, + }, } for name, tc := range cases { diff --git a/logical/framework/field_type.go b/logical/framework/field_type.go index a02b77bcd..d9d0ef3d2 100644 --- a/logical/framework/field_type.go +++ b/logical/framework/field_type.go @@ -9,6 +9,10 @@ const ( TypeInt TypeBool TypeMap + + // TypeDurationSecond represent as seconds, this can be either an + // integer or go duration format string (e.g. 24h) + TypeDurationSecond ) func (t FieldType) String() string { @@ -21,6 +25,8 @@ func (t FieldType) String() string { return "bool" case TypeMap: return "map" + case TypeDurationSecond: + return "duration (sec)" default: return "unknown type" }