diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/schema/resource.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/helper/schema/resource.go | 98 |
1 files changed, 82 insertions, 16 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go index ddba109..d3be2d6 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go | |||
@@ -85,6 +85,37 @@ type Resource struct { | |||
85 | Delete DeleteFunc | 85 | Delete DeleteFunc |
86 | Exists ExistsFunc | 86 | Exists ExistsFunc |
87 | 87 | ||
88 | // CustomizeDiff is a custom function for working with the diff that | ||
89 | // Terraform has created for this resource - it can be used to customize the | ||
90 | // diff that has been created, diff values not controlled by configuration, | ||
91 | // or even veto the diff altogether and abort the plan. It is passed a | ||
92 | // *ResourceDiff, a structure similar to ResourceData but lacking most write | ||
93 | // functions like Set, while introducing new functions that work with the | ||
94 | // diff such as SetNew, SetNewComputed, and ForceNew. | ||
95 | // | ||
96 | // The phases Terraform runs this in, and the state available via functions | ||
97 | // like Get and GetChange, are as follows: | ||
98 | // | ||
99 | // * New resource: One run with no state | ||
100 | // * Existing resource: One run with state | ||
101 | // * Existing resource, forced new: One run with state (before ForceNew), | ||
102 | // then one run without state (as if new resource) | ||
103 | // * Tainted resource: No runs (custom diff logic is skipped) | ||
104 | // * Destroy: No runs (standard diff logic is skipped on destroy diffs) | ||
105 | // | ||
106 | // This function needs to be resilient to support all scenarios. | ||
107 | // | ||
108 | // If this function needs to access external API resources, remember to flag | ||
109 | // the RequiresRefresh attribute mentioned below to ensure that | ||
110 | // -refresh=false is blocked when running plan or apply, as this means that | ||
111 | // this resource requires refresh-like behaviour to work effectively. | ||
112 | // | ||
113 | // For the most part, only computed fields can be customized by this | ||
114 | // function. | ||
115 | // | ||
116 | // This function is only allowed on regular resources (not data sources). | ||
117 | CustomizeDiff CustomizeDiffFunc | ||
118 | |||
88 | // Importer is the ResourceImporter implementation for this resource. | 119 | // Importer is the ResourceImporter implementation for this resource. |
89 | // If this is nil, then this resource does not support importing. If | 120 | // If this is nil, then this resource does not support importing. If |
90 | // this is non-nil, then it supports importing and ResourceImporter | 121 | // this is non-nil, then it supports importing and ResourceImporter |
@@ -93,9 +124,7 @@ type Resource struct { | |||
93 | Importer *ResourceImporter | 124 | Importer *ResourceImporter |
94 | 125 | ||
95 | // If non-empty, this string is emitted as a warning during Validate. | 126 | // If non-empty, this string is emitted as a warning during Validate. |
96 | // This is a private interface for now, for use by DataSourceResourceShim, | 127 | DeprecationMessage string |
97 | // and not for general use. (But maybe later...) | ||
98 | deprecationMessage string | ||
99 | 128 | ||
100 | // Timeouts allow users to specify specific time durations in which an | 129 | // Timeouts allow users to specify specific time durations in which an |
101 | // operation should time out, to allow them to extend an action to suit their | 130 | // operation should time out, to allow them to extend an action to suit their |
@@ -126,6 +155,9 @@ type ExistsFunc func(*ResourceData, interface{}) (bool, error) | |||
126 | type StateMigrateFunc func( | 155 | type StateMigrateFunc func( |
127 | int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error) | 156 | int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error) |
128 | 157 | ||
158 | // See Resource documentation. | ||
159 | type CustomizeDiffFunc func(*ResourceDiff, interface{}) error | ||
160 | |||
129 | // Apply creates, updates, and/or deletes a resource. | 161 | // Apply creates, updates, and/or deletes a resource. |
130 | func (r *Resource) Apply( | 162 | func (r *Resource) Apply( |
131 | s *terraform.InstanceState, | 163 | s *terraform.InstanceState, |
@@ -202,11 +234,11 @@ func (r *Resource) Apply( | |||
202 | return r.recordCurrentSchemaVersion(data.State()), err | 234 | return r.recordCurrentSchemaVersion(data.State()), err |
203 | } | 235 | } |
204 | 236 | ||
205 | // Diff returns a diff of this resource and is API compatible with the | 237 | // Diff returns a diff of this resource. |
206 | // ResourceProvider interface. | ||
207 | func (r *Resource) Diff( | 238 | func (r *Resource) Diff( |
208 | s *terraform.InstanceState, | 239 | s *terraform.InstanceState, |
209 | c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { | 240 | c *terraform.ResourceConfig, |
241 | meta interface{}) (*terraform.InstanceDiff, error) { | ||
210 | 242 | ||
211 | t := &ResourceTimeout{} | 243 | t := &ResourceTimeout{} |
212 | err := t.ConfigDecode(r, c) | 244 | err := t.ConfigDecode(r, c) |
@@ -215,7 +247,7 @@ func (r *Resource) Diff( | |||
215 | return nil, fmt.Errorf("[ERR] Error decoding timeout: %s", err) | 247 | return nil, fmt.Errorf("[ERR] Error decoding timeout: %s", err) |
216 | } | 248 | } |
217 | 249 | ||
218 | instanceDiff, err := schemaMap(r.Schema).Diff(s, c) | 250 | instanceDiff, err := schemaMap(r.Schema).Diff(s, c, r.CustomizeDiff, meta) |
219 | if err != nil { | 251 | if err != nil { |
220 | return instanceDiff, err | 252 | return instanceDiff, err |
221 | } | 253 | } |
@@ -235,8 +267,8 @@ func (r *Resource) Diff( | |||
235 | func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) { | 267 | func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) { |
236 | warns, errs := schemaMap(r.Schema).Validate(c) | 268 | warns, errs := schemaMap(r.Schema).Validate(c) |
237 | 269 | ||
238 | if r.deprecationMessage != "" { | 270 | if r.DeprecationMessage != "" { |
239 | warns = append(warns, r.deprecationMessage) | 271 | warns = append(warns, r.DeprecationMessage) |
240 | } | 272 | } |
241 | 273 | ||
242 | return warns, errs | 274 | return warns, errs |
@@ -248,7 +280,6 @@ func (r *Resource) ReadDataApply( | |||
248 | d *terraform.InstanceDiff, | 280 | d *terraform.InstanceDiff, |
249 | meta interface{}, | 281 | meta interface{}, |
250 | ) (*terraform.InstanceState, error) { | 282 | ) (*terraform.InstanceState, error) { |
251 | |||
252 | // Data sources are always built completely from scratch | 283 | // Data sources are always built completely from scratch |
253 | // on each read, so the source state is always nil. | 284 | // on each read, so the source state is always nil. |
254 | data, err := schemaMap(r.Schema).Data(nil, d) | 285 | data, err := schemaMap(r.Schema).Data(nil, d) |
@@ -346,6 +377,11 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error | |||
346 | if r.Create != nil || r.Update != nil || r.Delete != nil { | 377 | if r.Create != nil || r.Update != nil || r.Delete != nil { |
347 | return fmt.Errorf("must not implement Create, Update or Delete") | 378 | return fmt.Errorf("must not implement Create, Update or Delete") |
348 | } | 379 | } |
380 | |||
381 | // CustomizeDiff cannot be defined for read-only resources | ||
382 | if r.CustomizeDiff != nil { | ||
383 | return fmt.Errorf("cannot implement CustomizeDiff") | ||
384 | } | ||
349 | } | 385 | } |
350 | 386 | ||
351 | tsm := topSchemaMap | 387 | tsm := topSchemaMap |
@@ -393,19 +429,43 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error | |||
393 | return err | 429 | return err |
394 | } | 430 | } |
395 | } | 431 | } |
432 | |||
433 | for k, f := range tsm { | ||
434 | if isReservedResourceFieldName(k, f) { | ||
435 | return fmt.Errorf("%s is a reserved field name", k) | ||
436 | } | ||
437 | } | ||
396 | } | 438 | } |
397 | 439 | ||
398 | // Resource-specific checks | 440 | // Data source |
399 | for k, _ := range tsm { | 441 | if r.isTopLevel() && !writable { |
400 | if isReservedResourceFieldName(k) { | 442 | tsm = schemaMap(r.Schema) |
401 | return fmt.Errorf("%s is a reserved field name for a resource", k) | 443 | for k, _ := range tsm { |
444 | if isReservedDataSourceFieldName(k) { | ||
445 | return fmt.Errorf("%s is a reserved field name", k) | ||
446 | } | ||
402 | } | 447 | } |
403 | } | 448 | } |
404 | 449 | ||
405 | return schemaMap(r.Schema).InternalValidate(tsm) | 450 | return schemaMap(r.Schema).InternalValidate(tsm) |
406 | } | 451 | } |
407 | 452 | ||
408 | func isReservedResourceFieldName(name string) bool { | 453 | func isReservedDataSourceFieldName(name string) bool { |
454 | for _, reservedName := range config.ReservedDataSourceFields { | ||
455 | if name == reservedName { | ||
456 | return true | ||
457 | } | ||
458 | } | ||
459 | return false | ||
460 | } | ||
461 | |||
462 | func isReservedResourceFieldName(name string, s *Schema) bool { | ||
463 | // Allow phasing out "id" | ||
464 | // See https://github.com/terraform-providers/terraform-provider-aws/pull/1626#issuecomment-328881415 | ||
465 | if name == "id" && (s.Deprecated != "" || s.Removed != "") { | ||
466 | return false | ||
467 | } | ||
468 | |||
409 | for _, reservedName := range config.ReservedResourceFields { | 469 | for _, reservedName := range config.ReservedResourceFields { |
410 | if name == reservedName { | 470 | if name == reservedName { |
411 | return true | 471 | return true |
@@ -430,6 +490,12 @@ func (r *Resource) Data(s *terraform.InstanceState) *ResourceData { | |||
430 | panic(err) | 490 | panic(err) |
431 | } | 491 | } |
432 | 492 | ||
493 | // load the Resource timeouts | ||
494 | result.timeouts = r.Timeouts | ||
495 | if result.timeouts == nil { | ||
496 | result.timeouts = &ResourceTimeout{} | ||
497 | } | ||
498 | |||
433 | // Set the schema version to latest by default | 499 | // Set the schema version to latest by default |
434 | result.meta = map[string]interface{}{ | 500 | result.meta = map[string]interface{}{ |
435 | "schema_version": strconv.Itoa(r.SchemaVersion), | 501 | "schema_version": strconv.Itoa(r.SchemaVersion), |
@@ -450,7 +516,7 @@ func (r *Resource) TestResourceData() *ResourceData { | |||
450 | // Returns true if the resource is "top level" i.e. not a sub-resource. | 516 | // Returns true if the resource is "top level" i.e. not a sub-resource. |
451 | func (r *Resource) isTopLevel() bool { | 517 | func (r *Resource) isTopLevel() bool { |
452 | // TODO: This is a heuristic; replace with a definitive attribute? | 518 | // TODO: This is a heuristic; replace with a definitive attribute? |
453 | return r.Create != nil | 519 | return (r.Create != nil || r.Read != nil) |
454 | } | 520 | } |
455 | 521 | ||
456 | // Determines if a given InstanceState needs to be migrated by checking the | 522 | // Determines if a given InstanceState needs to be migrated by checking the |