helper/schema: DefaultFunc for dynamic defaults
/cc @c4milo - This might be useful to you as well.
This commit is contained in:
parent
e8d09da6fa
commit
0250c17d6e
|
@ -64,7 +64,15 @@ type Schema struct {
|
|||
|
||||
// If this is non-nil, then this will be a default value that is used
|
||||
// when this item is not set in the configuration/state.
|
||||
//
|
||||
// DefaultFunc can be specified if you want a dynamic default value.
|
||||
// Only one of Default or DefaultFunc can be set.
|
||||
//
|
||||
// If Required is true above, then Default cannot be set. DefaultFunc
|
||||
// can be set with Required. If the DefaultFunc returns nil, then there
|
||||
// will no default and the user will be asked to fill it in.
|
||||
Default interface{}
|
||||
DefaultFunc SchemaDefaultFunc
|
||||
|
||||
// The fields below relate to diffs.
|
||||
//
|
||||
|
@ -104,6 +112,10 @@ type Schema struct {
|
|||
ComputedWhen []string
|
||||
}
|
||||
|
||||
// SchemaDefaultFunc is a function called to return a default value for
|
||||
// a field.
|
||||
type SchemaDefaultFunc func() (interface{}, error)
|
||||
|
||||
// SchemaSetFunc is a function that must return a unique ID for the given
|
||||
// element. This unique ID is used to store the element in a hash.
|
||||
type SchemaSetFunc func(interface{}) int
|
||||
|
@ -288,6 +300,10 @@ func (m schemaMap) InternalValidate() error {
|
|||
return fmt.Errorf("%s: Default must be nil if computed", k)
|
||||
}
|
||||
|
||||
if v.Required && v.Default != nil {
|
||||
return fmt.Errorf("%s: Default cannot be set with Required", k)
|
||||
}
|
||||
|
||||
if len(v.ComputedWhen) > 0 && !v.Computed {
|
||||
return fmt.Errorf("%s: ComputedWhen can only be set with Computed", k)
|
||||
}
|
||||
|
@ -506,6 +522,13 @@ func (m schemaMap) diffString(
|
|||
o, n, _ := d.diffChange(k)
|
||||
if n == nil {
|
||||
n = schema.Default
|
||||
if schema.DefaultFunc != nil {
|
||||
var err error
|
||||
n, err = schema.DefaultFunc()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s, error loading default: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if schema.StateFunc != nil {
|
||||
originalN = n
|
||||
|
@ -551,6 +574,18 @@ func (m schemaMap) validate(
|
|||
schema *Schema,
|
||||
c *terraform.ResourceConfig) ([]string, []error) {
|
||||
raw, ok := c.Get(k)
|
||||
if !ok && schema.DefaultFunc != nil {
|
||||
// We have a dynamic default. Check if we have a value.
|
||||
var err error
|
||||
raw, err = schema.DefaultFunc()
|
||||
if err != nil {
|
||||
return nil, []error{fmt.Errorf(
|
||||
"%s, error loading default: %s", k, err)}
|
||||
}
|
||||
|
||||
// We're okay as long as we had a value set
|
||||
ok = raw != nil
|
||||
}
|
||||
if !ok {
|
||||
if schema.Required {
|
||||
return nil, []error{fmt.Errorf(
|
||||
|
|
|
@ -124,6 +124,64 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// DefaultFunc, value
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "foo", nil
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: nil,
|
||||
|
||||
Diff: &terraform.ResourceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"availability_zone": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
// DefaultFunc, configuration set
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "foo", nil
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"availability_zone": "bar",
|
||||
},
|
||||
|
||||
Diff: &terraform.ResourceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"availability_zone": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
// String with StateFunc
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
|
@ -1055,6 +1113,19 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
|
|||
true,
|
||||
},
|
||||
|
||||
// Required but has default
|
||||
{
|
||||
map[string]*Schema{
|
||||
"foo": &Schema{
|
||||
Type: TypeInt,
|
||||
Optional: true,
|
||||
Required: true,
|
||||
Default: "foo",
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
|
||||
// List element not set
|
||||
{
|
||||
map[string]*Schema{
|
||||
|
@ -1227,6 +1298,38 @@ func TestSchemaMap_Validate(t *testing.T) {
|
|||
Err: true,
|
||||
},
|
||||
|
||||
// Required but has DefaultFunc
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return "foo", nil
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Config: nil,
|
||||
},
|
||||
|
||||
// Required but has DefaultFunc return nil
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
Type: TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return nil, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Config: nil,
|
||||
|
||||
Err: true,
|
||||
},
|
||||
|
||||
// Optional sub-resource
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
|
|
Loading…
Reference in New Issue