Merge pull request #8585 from hashicorp/f-diff-suppression
helper/schema: Add diff suppression callback
This commit is contained in:
commit
bf755bb5c9
|
@ -21,26 +21,24 @@ func resourceDigitalOceanSSHKey() *schema.Resource {
|
||||||
},
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"id": &schema.Schema{
|
"id": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
"name": &schema.Schema{
|
"name": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
"public_key": &schema.Schema{
|
"public_key": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
StateFunc: func(val interface{}) string {
|
DiffSuppressFunc: resourceDigitalOceanSSHKeyPublicKeyDiffSuppress,
|
||||||
return strings.TrimSpace(val.(string))
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"fingerprint": &schema.Schema{
|
"fingerprint": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
@ -48,6 +46,10 @@ func resourceDigitalOceanSSHKey() *schema.Resource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceDigitalOceanSSHKeyPublicKeyDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
|
||||||
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
||||||
|
}
|
||||||
|
|
||||||
func resourceDigitalOceanSSHKeyCreate(d *schema.ResourceData, meta interface{}) error {
|
func resourceDigitalOceanSSHKeyCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
client := meta.(*godo.Client)
|
client := meta.(*godo.Client)
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,15 @@ type Schema struct {
|
||||||
Optional bool
|
Optional bool
|
||||||
Required bool
|
Required bool
|
||||||
|
|
||||||
|
// If this is non-nil, the provided function will be used during diff
|
||||||
|
// of this field. If this is nil, a default diff for the type of the
|
||||||
|
// schema will be used.
|
||||||
|
//
|
||||||
|
// This allows comparison based on something other than primitive, list
|
||||||
|
// or map equality - for example SSH public keys may be considered
|
||||||
|
// equivalent regardless of trailing whitespace.
|
||||||
|
DiffSuppressFunc SchemaDiffSuppressFunc
|
||||||
|
|
||||||
// If this is non-nil, then this will be a default value that is used
|
// 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.
|
// when this item is not set in the configuration/state.
|
||||||
//
|
//
|
||||||
|
@ -153,6 +162,13 @@ type Schema struct {
|
||||||
Sensitive bool
|
Sensitive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SchemaDiffSuppresFunc is a function which can be used to determine
|
||||||
|
// whether a detected diff on a schema element is "valid" or not, and
|
||||||
|
// suppress it from the plan if necessary.
|
||||||
|
//
|
||||||
|
// Return true if the diff should be suppressed, false to retain it.
|
||||||
|
type SchemaDiffSuppressFunc func(k, old, new string, d *ResourceData) bool
|
||||||
|
|
||||||
// SchemaDefaultFunc is a function called to return a default value for
|
// SchemaDefaultFunc is a function called to return a default value for
|
||||||
// a field.
|
// a field.
|
||||||
type SchemaDefaultFunc func() (interface{}, error)
|
type SchemaDefaultFunc func() (interface{}, error)
|
||||||
|
@ -603,20 +619,32 @@ func (m schemaMap) diff(
|
||||||
diff *terraform.InstanceDiff,
|
diff *terraform.InstanceDiff,
|
||||||
d *ResourceData,
|
d *ResourceData,
|
||||||
all bool) error {
|
all bool) error {
|
||||||
|
|
||||||
|
unsupressedDiff := new(terraform.InstanceDiff)
|
||||||
|
unsupressedDiff.Attributes = make(map[string]*terraform.ResourceAttrDiff)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool, TypeInt, TypeFloat, TypeString:
|
case TypeBool, TypeInt, TypeFloat, TypeString:
|
||||||
err = m.diffString(k, schema, diff, d, all)
|
err = m.diffString(k, schema, unsupressedDiff, d, all)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
err = m.diffList(k, schema, diff, d, all)
|
err = m.diffList(k, schema, unsupressedDiff, d, all)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
err = m.diffMap(k, schema, diff, d, all)
|
err = m.diffMap(k, schema, unsupressedDiff, d, all)
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
err = m.diffSet(k, schema, diff, d, all)
|
err = m.diffSet(k, schema, unsupressedDiff, d, all)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("%s: unknown type %#v", k, schema.Type)
|
err = fmt.Errorf("%s: unknown type %#v", k, schema.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for attrK, attrV := range unsupressedDiff.Attributes {
|
||||||
|
if schema.DiffSuppressFunc != nil && schema.DiffSuppressFunc(attrK, attrV.Old, attrV.New, d) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
diff.Attributes[attrK] = attrV
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2939,6 +2939,92 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSchemaMap_DiffSuppress(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
Schema map[string]*Schema
|
||||||
|
State *terraform.InstanceState
|
||||||
|
Config map[string]interface{}
|
||||||
|
ConfigVariables map[string]ast.Variable
|
||||||
|
ExpectedDiff *terraform.InstanceDiff
|
||||||
|
Err bool
|
||||||
|
}{
|
||||||
|
"#0 - Suppress otherwise valid diff by returning true": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": {
|
||||||
|
Type: TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
|
||||||
|
// Always suppress any diff
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"availability_zone": "foo",
|
||||||
|
},
|
||||||
|
|
||||||
|
ExpectedDiff: nil,
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
},
|
||||||
|
"#1 - Don't suppress diff by returning false": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"availability_zone": {
|
||||||
|
Type: TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DiffSuppressFunc: func(k, old, new string, d *ResourceData) bool {
|
||||||
|
// Always suppress any diff
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
State: nil,
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"availability_zone": "foo",
|
||||||
|
},
|
||||||
|
|
||||||
|
ExpectedDiff: &terraform.InstanceDiff{
|
||||||
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||||
|
"availability_zone": {
|
||||||
|
Old: "",
|
||||||
|
New: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tn, tc := range cases {
|
||||||
|
c, err := config.NewRawConfig(tc.Config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("#%q err: %s", tn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tc.ConfigVariables) > 0 {
|
||||||
|
if err := c.Interpolate(tc.ConfigVariables); err != nil {
|
||||||
|
t.Fatalf("#%q err: %s", tn, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := schemaMap(tc.Schema).Diff(
|
||||||
|
tc.State, terraform.NewResourceConfig(c))
|
||||||
|
if err != nil != tc.Err {
|
||||||
|
t.Fatalf("#%q err: %s", tn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tc.ExpectedDiff, d) {
|
||||||
|
t.Fatalf("#%q:\n\nexpected:\n%#v\n\ngot:\n%#v", tn, tc.ExpectedDiff, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSchemaMap_Validate(t *testing.T) {
|
func TestSchemaMap_Validate(t *testing.T) {
|
||||||
cases := map[string]struct {
|
cases := map[string]struct {
|
||||||
Schema map[string]*Schema
|
Schema map[string]*Schema
|
||||||
|
|
Loading…
Reference in New Issue