diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go index bc8e1c3c1..e716e288f 100644 --- a/helper/schema/resource_data.go +++ b/helper/schema/resource_data.go @@ -28,6 +28,7 @@ const ( type getResult struct { Value interface{} Exists bool + Schema *Schema } var getResultEmpty getResult @@ -200,6 +201,10 @@ func (d *ResourceData) diffChange(k string) (interface{}, interface{}, bool) { n.Value = nil } + if n.Exists && n.Schema.StateFunc != nil { + n.Value = n.Schema.StateFunc(n.Value) + } + // Return the old, new, and whether there is a change return o.Value, n.Value, !reflect.DeepEqual(o.Value, n.Value) } @@ -248,7 +253,7 @@ func (d *ResourceData) getSet( schema *Schema, source getSource) getResult { s := &Set{F: schema.Set} - result := getResult{Value: s} + result := getResult{Schema: schema, Value: s} raw := d.getList(k, nil, schema, source) if !raw.Exists { if len(parts) > 0 { @@ -394,6 +399,7 @@ func (d *ResourceData) getMap( return getResult{ Value: resultValue, Exists: resultSet, + Schema: schema, } } @@ -429,6 +435,9 @@ func (d *ResourceData) getObject( return getResult{ Value: result, Exists: true, + Schema: &Schema{ + Elem: schema, + }, } } @@ -469,6 +478,7 @@ func (d *ResourceData) getList( return getResult{ Value: result, Exists: count.Exists, + Schema: schema, } } @@ -553,6 +563,7 @@ func (d *ResourceData) getPrimitive( return getResult{ Value: resultValue, Exists: resultSet, + Schema: schema, } } diff --git a/helper/schema/resource_data_test.go b/helper/schema/resource_data_test.go index f701bbc85..ba07eca50 100644 --- a/helper/schema/resource_data_test.go +++ b/helper/schema/resource_data_test.go @@ -1430,6 +1430,35 @@ func TestResourceDataState(t *testing.T) { }, }, + // Basic primitive with StateFunc set + { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Optional: true, + Computed: true, + StateFunc: func(interface{}) string { return "" }, + }, + }, + + State: nil, + + Diff: &terraform.ResourceDiff{ + Attributes: map[string]*terraform.ResourceAttrDiff{ + "availability_zone": &terraform.ResourceAttrDiff{ + Old: "", + New: "foo", + }, + }, + }, + + Result: &terraform.ResourceState{ + Attributes: map[string]string{ + "availability_zone": "foo", + }, + }, + }, + // List { Schema: map[string]*Schema{ diff --git a/helper/schema/schema.go b/helper/schema/schema.go index 0b3383263..23f5c34fa 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -41,8 +41,14 @@ type Schema struct { // // If ForceNew is true, then a change in this resource necessitates // the creation of a new resource. - Computed bool - ForceNew bool + // + // StateFunc is a function called to change the value of this before + // storing it in the state (and likewise before comparing for diffs). + // The use for this is for example with large strings, you may want + // to simply store the hash of it. + Computed bool + ForceNew bool + StateFunc SchemaStateFunc // The following fields are only set for a TypeList or TypeSet Type. // @@ -66,7 +72,11 @@ type Schema struct { // 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(a interface{}) int +type SchemaSetFunc func(interface{}) int + +// SchemaStateFunc is a function used to convert some type to a string +// to be stored in the state. +type SchemaStateFunc func(interface{}) string func (s *Schema) finalizeDiff( d *terraform.ResourceAttrDiff) *terraform.ResourceAttrDiff { diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index ee06514fe..b457d4f89 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -76,6 +76,37 @@ func TestSchemaMap_Diff(t *testing.T) { Err: false, }, + // String with StateFunc + { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Optional: true, + Computed: true, + StateFunc: func(a interface{}) string { + return a.(string) + "!" + }, + }, + }, + + State: nil, + + Config: map[string]interface{}{ + "availability_zone": "foo", + }, + + Diff: &terraform.ResourceDiff{ + Attributes: map[string]*terraform.ResourceAttrDiff{ + "availability_zone": &terraform.ResourceAttrDiff{ + Old: "", + New: "foo!", + }, + }, + }, + + Err: false, + }, + /* * Int decode */