diff --git a/helper/schema/schema.go b/helper/schema/schema.go index e05acd395a..54df8e0a1d 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -113,6 +113,13 @@ type Schema struct { // // NOTE: This currently does not work. ComputedWhen []string + + // When Deprecated is set, this field is deprecated. + // + // A deprecated field still works, but will probably stop working in near + // future. This string is the message shown to the user with instructions on + // how to address the deprecation. + Deprecated string } // SchemaDefaultFunc is a function called to return a default value for @@ -877,7 +884,7 @@ func (m schemaMap) validate( raw, err = schema.DefaultFunc() if err != nil { return nil, []error{fmt.Errorf( - "%s, error loading default: %s", k, err)} + "%q, error loading default: %s", k, err)} } // We're okay as long as we had a value set @@ -886,7 +893,7 @@ func (m schemaMap) validate( if !ok { if schema.Required { return nil, []error{fmt.Errorf( - "%s: required field is not set", k)} + "%q: required field is not set", k)} } return nil, nil @@ -895,7 +902,7 @@ func (m schemaMap) validate( if !schema.Required && !schema.Optional { // This is a computed-only field return nil, []error{fmt.Errorf( - "%s: this field cannot be set", k)} + "%q: this field cannot be set", k)} } return m.validateType(k, raw, schema, c) @@ -1066,16 +1073,25 @@ func (m schemaMap) validateType( raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { + var ws []string + var es []error switch schema.Type { case TypeSet: fallthrough case TypeList: - return m.validateList(k, raw, schema, c) + ws, es = m.validateList(k, raw, schema, c) case TypeMap: - return m.validateMap(k, raw, schema, c) + ws, es = m.validateMap(k, raw, schema, c) default: - return m.validatePrimitive(k, raw, schema, c) + ws, es = m.validatePrimitive(k, raw, schema, c) } + + if schema.Deprecated != "" { + ws = append(ws, fmt.Sprintf( + "%q: [DEPRECATED] %s", k, schema.Deprecated)) + } + + return ws, es } // Zero returns the zero value for a type. diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 81089121c9..b64aa29904 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -2584,11 +2584,11 @@ func TestSchemaMap_InternalValidate(t *testing.T) { func TestSchemaMap_Validate(t *testing.T) { cases := map[string]struct { - Schema map[string]*Schema - Config map[string]interface{} - Vars map[string]string - Warn bool - Err bool + Schema map[string]*Schema + Config map[string]interface{} + Vars map[string]string + Err bool + Warnings []string }{ "Good": { Schema: map[string]*Schema{ @@ -3019,6 +3019,83 @@ func TestSchemaMap_Validate(t *testing.T) { Err: true, }, + + "Deprecated attribute usage generates warning, but not error": { + Schema: map[string]*Schema{ + "old_news": &Schema{ + Type: TypeString, + Optional: true, + Deprecated: "please use 'new_news' instead", + }, + }, + + Config: map[string]interface{}{ + "old_news": "extra extra!", + }, + + Err: false, + + Warnings: []string{ + "\"old_news\": [DEPRECATED] please use 'new_news' instead", + }, + }, + + "Deprecated generates no warnings if attr not used": { + Schema: map[string]*Schema{ + "old_news": &Schema{ + Type: TypeString, + Optional: true, + Deprecated: "please use 'new_news' instead", + }, + }, + + Err: false, + + Warnings: nil, + }, + + "Deprecated works with set/list type": { + Schema: map[string]*Schema{ + "old_news": &Schema{ + Type: TypeSet, + Optional: true, + Elem: &Schema{Type: TypeString}, + Deprecated: "please use 'new_news' instead", + }, + }, + + Config: map[string]interface{}{ + "old_news": []interface{}{"extra extra!"}, + }, + + Err: false, + + Warnings: []string{ + "\"old_news\": [DEPRECATED] please use 'new_news' instead", + }, + }, + + "Deprecated works with map type": { + Schema: map[string]*Schema{ + "old_news": &Schema{ + Type: TypeMap, + Optional: true, + Deprecated: "please use 'new_news' instead", + }, + }, + + Config: map[string]interface{}{ + "old_news": map[string]interface{}{ + "foo": "bar", + }, + }, + + Err: false, + + Warnings: []string{ + "\"old_news\": [DEPRECATED] please use 'new_news' instead", + }, + }, } for tn, tc := range cases { @@ -3050,8 +3127,8 @@ func TestSchemaMap_Validate(t *testing.T) { t.FailNow() } - if (len(ws) > 0) != tc.Warn { - t.Fatalf("%q: ws: %#v", tn, ws) + if !reflect.DeepEqual(ws, tc.Warnings) { + t.Fatalf("%q: warnings:\n\nexpected: %#v\ngot:%#v", tn, tc.Warnings, ws) } } }