Merge pull request #1134 from hashicorp/f-deprecation

helper/schema: allow Schema attrs to be Deprecated/Removed
This commit is contained in:
Paul Hinze 2015-03-05 15:41:38 -06:00
commit e97b4803d6
2 changed files with 114 additions and 13 deletions

View File

@ -113,6 +113,21 @@ type Schema struct {
// //
// NOTE: This currently does not work. // NOTE: This currently does not work.
ComputedWhen []string ComputedWhen []string
// When Deprecated is set, this attribute 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
// When Removed is set, this attribute has been removed from the schema
//
// Removed attributes can be left in the Schema to generate informative error
// messages for the user when they show up in resource configurations.
// This string is the message shown to the user with instructions on
// what do to about the removed attribute.
Removed string
} }
// SchemaDefaultFunc is a function called to return a default value for // SchemaDefaultFunc is a function called to return a default value for
@ -877,7 +892,7 @@ func (m schemaMap) validate(
raw, err = schema.DefaultFunc() raw, err = schema.DefaultFunc()
if err != nil { if err != nil {
return nil, []error{fmt.Errorf( 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 // We're okay as long as we had a value set
@ -886,7 +901,7 @@ func (m schemaMap) validate(
if !ok { if !ok {
if schema.Required { if schema.Required {
return nil, []error{fmt.Errorf( return nil, []error{fmt.Errorf(
"%s: required field is not set", k)} "%q: required field is not set", k)}
} }
return nil, nil return nil, nil
@ -895,7 +910,7 @@ func (m schemaMap) validate(
if !schema.Required && !schema.Optional { if !schema.Required && !schema.Optional {
// This is a computed-only field // This is a computed-only field
return nil, []error{fmt.Errorf( 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) return m.validateType(k, raw, schema, c)
@ -1066,16 +1081,30 @@ func (m schemaMap) validateType(
raw interface{}, raw interface{},
schema *Schema, schema *Schema,
c *terraform.ResourceConfig) ([]string, []error) { c *terraform.ResourceConfig) ([]string, []error) {
var ws []string
var es []error
switch schema.Type { switch schema.Type {
case TypeSet: case TypeSet:
fallthrough fallthrough
case TypeList: case TypeList:
return m.validateList(k, raw, schema, c) ws, es = m.validateList(k, raw, schema, c)
case TypeMap: case TypeMap:
return m.validateMap(k, raw, schema, c) ws, es = m.validateMap(k, raw, schema, c)
default: 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))
}
if schema.Removed != "" {
es = append(es, fmt.Errorf(
"%q: [REMOVED] %s", k, schema.Removed))
}
return ws, es
} }
// Zero returns the zero value for a type. // Zero returns the zero value for a type.

View File

@ -2587,8 +2587,9 @@ func TestSchemaMap_Validate(t *testing.T) {
Schema map[string]*Schema Schema map[string]*Schema
Config map[string]interface{} Config map[string]interface{}
Vars map[string]string Vars map[string]string
Warn bool
Err bool Err bool
Errors []error
Warnings []string
}{ }{
"Good": { "Good": {
Schema: map[string]*Schema{ Schema: map[string]*Schema{
@ -3019,6 +3020,71 @@ func TestSchemaMap_Validate(t *testing.T) {
Err: true, 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,
},
"Removed attribute usage generates error": {
Schema: map[string]*Schema{
"long_gone": &Schema{
Type: TypeString,
Optional: true,
Removed: "no longer supported by Cloud API",
},
},
Config: map[string]interface{}{
"long_gone": "still here!",
},
Err: true,
Errors: []error{
fmt.Errorf("\"long_gone\": [REMOVED] no longer supported by Cloud API"),
},
},
"Removed generates no errors if attr not used": {
Schema: map[string]*Schema{
"long_gone": &Schema{
Type: TypeString,
Optional: true,
Removed: "no longer supported by Cloud API",
},
},
Err: false,
},
} }
for tn, tc := range cases { for tn, tc := range cases {
@ -3050,8 +3116,14 @@ func TestSchemaMap_Validate(t *testing.T) {
t.FailNow() t.FailNow()
} }
if (len(ws) > 0) != tc.Warn { if !reflect.DeepEqual(ws, tc.Warnings) {
t.Fatalf("%q: ws: %#v", tn, ws) t.Fatalf("%q: warnings:\n\nexpected: %#v\ngot:%#v", tn, tc.Warnings, ws)
}
if tc.Errors != nil {
if !reflect.DeepEqual(es, tc.Errors) {
t.Fatalf("%q: errors:\n\nexpected: %q\ngot: %q", tn, tc.Errors, es)
}
} }
} }
} }