aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go192
1 files changed, 173 insertions, 19 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go b/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go
index bf952f6..875677e 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go
@@ -3,7 +3,7 @@ package schema
3import ( 3import (
4 "fmt" 4 "fmt"
5 5
6 "github.com/hashicorp/terraform/config/configschema" 6 "github.com/hashicorp/terraform/configs/configschema"
7 "github.com/zclconf/go-cty/cty" 7 "github.com/zclconf/go-cty/cty"
8) 8)
9 9
@@ -39,14 +39,42 @@ func (m schemaMap) CoreConfigSchema() *configschema.Block {
39 ret.Attributes[name] = schema.coreConfigSchemaAttribute() 39 ret.Attributes[name] = schema.coreConfigSchemaAttribute()
40 continue 40 continue
41 } 41 }
42 switch schema.Elem.(type) { 42 if schema.Type == TypeMap {
43 case *Schema: 43 // For TypeMap in particular, it isn't valid for Elem to be a
44 // *Resource (since that would be ambiguous in flatmap) and
45 // so Elem is treated as a TypeString schema if so. This matches
46 // how the field readers treat this situation, for compatibility
47 // with configurations targeting Terraform 0.11 and earlier.
48 if _, isResource := schema.Elem.(*Resource); isResource {
49 sch := *schema // shallow copy
50 sch.Elem = &Schema{
51 Type: TypeString,
52 }
53 ret.Attributes[name] = sch.coreConfigSchemaAttribute()
54 continue
55 }
56 }
57 switch schema.ConfigMode {
58 case SchemaConfigModeAttr:
44 ret.Attributes[name] = schema.coreConfigSchemaAttribute() 59 ret.Attributes[name] = schema.coreConfigSchemaAttribute()
45 case *Resource: 60 case SchemaConfigModeBlock:
46 ret.BlockTypes[name] = schema.coreConfigSchemaBlock() 61 ret.BlockTypes[name] = schema.coreConfigSchemaBlock()
47 default: 62 default: // SchemaConfigModeAuto, or any other invalid value
48 // Should never happen for a valid schema 63 if schema.Computed && !schema.Optional {
49 panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", schema.Elem)) 64 // Computed-only schemas are always handled as attributes,
65 // because they never appear in configuration.
66 ret.Attributes[name] = schema.coreConfigSchemaAttribute()
67 continue
68 }
69 switch schema.Elem.(type) {
70 case *Schema, ValueType:
71 ret.Attributes[name] = schema.coreConfigSchemaAttribute()
72 case *Resource:
73 ret.BlockTypes[name] = schema.coreConfigSchemaBlock()
74 default:
75 // Should never happen for a valid schema
76 panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", schema.Elem))
77 }
50 } 78 }
51 } 79 }
52 80
@@ -58,12 +86,42 @@ func (m schemaMap) CoreConfigSchema() *configschema.Block {
58// Elem is an instance of Schema. Use coreConfigSchemaBlock for collections 86// Elem is an instance of Schema. Use coreConfigSchemaBlock for collections
59// whose elem is a whole resource. 87// whose elem is a whole resource.
60func (s *Schema) coreConfigSchemaAttribute() *configschema.Attribute { 88func (s *Schema) coreConfigSchemaAttribute() *configschema.Attribute {
89 // The Schema.DefaultFunc capability adds some extra weirdness here since
90 // it can be combined with "Required: true" to create a sitution where
91 // required-ness is conditional. Terraform Core doesn't share this concept,
92 // so we must sniff for this possibility here and conditionally turn
93 // off the "Required" flag if it looks like the DefaultFunc is going
94 // to provide a value.
95 // This is not 100% true to the original interface of DefaultFunc but
96 // works well enough for the EnvDefaultFunc and MultiEnvDefaultFunc
97 // situations, which are the main cases we care about.
98 //
99 // Note that this also has a consequence for commands that return schema
100 // information for documentation purposes: running those for certain
101 // providers will produce different results depending on which environment
102 // variables are set. We accept that weirdness in order to keep this
103 // interface to core otherwise simple.
104 reqd := s.Required
105 opt := s.Optional
106 if reqd && s.DefaultFunc != nil {
107 v, err := s.DefaultFunc()
108 // We can't report errors from here, so we'll instead just force
109 // "Required" to false and let the provider try calling its
110 // DefaultFunc again during the validate step, where it can then
111 // return the error.
112 if err != nil || (err == nil && v != nil) {
113 reqd = false
114 opt = true
115 }
116 }
117
61 return &configschema.Attribute{ 118 return &configschema.Attribute{
62 Type: s.coreConfigSchemaType(), 119 Type: s.coreConfigSchemaType(),
63 Optional: s.Optional, 120 Optional: opt,
64 Required: s.Required, 121 Required: reqd,
65 Computed: s.Computed, 122 Computed: s.Computed,
66 Sensitive: s.Sensitive, 123 Sensitive: s.Sensitive,
124 Description: s.Description,
67 } 125 }
68} 126}
69 127
@@ -72,7 +130,7 @@ func (s *Schema) coreConfigSchemaAttribute() *configschema.Attribute {
72// of Resource, and will panic otherwise. 130// of Resource, and will panic otherwise.
73func (s *Schema) coreConfigSchemaBlock() *configschema.NestedBlock { 131func (s *Schema) coreConfigSchemaBlock() *configschema.NestedBlock {
74 ret := &configschema.NestedBlock{} 132 ret := &configschema.NestedBlock{}
75 if nested := s.Elem.(*Resource).CoreConfigSchema(); nested != nil { 133 if nested := s.Elem.(*Resource).coreConfigSchema(); nested != nil {
76 ret.Block = *nested 134 ret.Block = *nested
77 } 135 }
78 switch s.Type { 136 switch s.Type {
@@ -95,6 +153,20 @@ func (s *Schema) coreConfigSchemaBlock() *configschema.NestedBlock {
95 // blocks, but we can fake it by requiring at least one item. 153 // blocks, but we can fake it by requiring at least one item.
96 ret.MinItems = 1 154 ret.MinItems = 1
97 } 155 }
156 if s.Optional && s.MinItems > 0 {
157 // Historically helper/schema would ignore MinItems if Optional were
158 // set, so we must mimic this behavior here to ensure that providers
159 // relying on that undocumented behavior can continue to operate as
160 // they did before.
161 ret.MinItems = 0
162 }
163 if s.Computed && !s.Optional {
164 // MinItems/MaxItems are meaningless for computed nested blocks, since
165 // they are never set by the user anyway. This ensures that we'll never
166 // generate weird errors about them.
167 ret.MinItems = 0
168 ret.MaxItems = 0
169 }
98 170
99 return ret 171 return ret
100} 172}
@@ -117,11 +189,16 @@ func (s *Schema) coreConfigSchemaType() cty.Type {
117 switch set := s.Elem.(type) { 189 switch set := s.Elem.(type) {
118 case *Schema: 190 case *Schema:
119 elemType = set.coreConfigSchemaType() 191 elemType = set.coreConfigSchemaType()
192 case ValueType:
193 // This represents a mistake in the provider code, but it's a
194 // common one so we'll just shim it.
195 elemType = (&Schema{Type: set}).coreConfigSchemaType()
120 case *Resource: 196 case *Resource:
121 // In practice we don't actually use this for normal schema 197 // By default we construct a NestedBlock in this case, but this
122 // construction because we construct a NestedBlock in that 198 // behavior is selected either for computed-only schemas or
123 // case instead. See schemaMap.CoreConfigSchema. 199 // when ConfigMode is explicitly SchemaConfigModeBlock.
124 elemType = set.CoreConfigSchema().ImpliedType() 200 // See schemaMap.CoreConfigSchema for the exact rules.
201 elemType = set.coreConfigSchema().ImpliedType()
125 default: 202 default:
126 if set != nil { 203 if set != nil {
127 // Should never happen for a valid schema 204 // Should never happen for a valid schema
@@ -148,8 +225,85 @@ func (s *Schema) coreConfigSchemaType() cty.Type {
148 } 225 }
149} 226}
150 227
151// CoreConfigSchema is a convenient shortcut for calling CoreConfigSchema 228// CoreConfigSchema is a convenient shortcut for calling CoreConfigSchema on
152// on the resource's schema. 229// the resource's schema. CoreConfigSchema adds the implicitly required "id"
230// attribute for top level resources if it doesn't exist.
153func (r *Resource) CoreConfigSchema() *configschema.Block { 231func (r *Resource) CoreConfigSchema() *configschema.Block {
232 block := r.coreConfigSchema()
233
234 if block.Attributes == nil {
235 block.Attributes = map[string]*configschema.Attribute{}
236 }
237
238 // Add the implicitly required "id" field if it doesn't exist
239 if block.Attributes["id"] == nil {
240 block.Attributes["id"] = &configschema.Attribute{
241 Type: cty.String,
242 Optional: true,
243 Computed: true,
244 }
245 }
246
247 _, timeoutsAttr := block.Attributes[TimeoutsConfigKey]
248 _, timeoutsBlock := block.BlockTypes[TimeoutsConfigKey]
249
250 // Insert configured timeout values into the schema, as long as the schema
251 // didn't define anything else by that name.
252 if r.Timeouts != nil && !timeoutsAttr && !timeoutsBlock {
253 timeouts := configschema.Block{
254 Attributes: map[string]*configschema.Attribute{},
255 }
256
257 if r.Timeouts.Create != nil {
258 timeouts.Attributes[TimeoutCreate] = &configschema.Attribute{
259 Type: cty.String,
260 Optional: true,
261 }
262 }
263
264 if r.Timeouts.Read != nil {
265 timeouts.Attributes[TimeoutRead] = &configschema.Attribute{
266 Type: cty.String,
267 Optional: true,
268 }
269 }
270
271 if r.Timeouts.Update != nil {
272 timeouts.Attributes[TimeoutUpdate] = &configschema.Attribute{
273 Type: cty.String,
274 Optional: true,
275 }
276 }
277
278 if r.Timeouts.Delete != nil {
279 timeouts.Attributes[TimeoutDelete] = &configschema.Attribute{
280 Type: cty.String,
281 Optional: true,
282 }
283 }
284
285 if r.Timeouts.Default != nil {
286 timeouts.Attributes[TimeoutDefault] = &configschema.Attribute{
287 Type: cty.String,
288 Optional: true,
289 }
290 }
291
292 block.BlockTypes[TimeoutsConfigKey] = &configschema.NestedBlock{
293 Nesting: configschema.NestingSingle,
294 Block: timeouts,
295 }
296 }
297
298 return block
299}
300
301func (r *Resource) coreConfigSchema() *configschema.Block {
302 return schemaMap(r.Schema).CoreConfigSchema()
303}
304
305// CoreConfigSchema is a convenient shortcut for calling CoreConfigSchema
306// on the backends's schema.
307func (r *Backend) CoreConfigSchema() *configschema.Block {
154 return schemaMap(r.Schema).CoreConfigSchema() 308 return schemaMap(r.Schema).CoreConfigSchema()
155} 309}