/
schema.go
443 lines (374 loc) · 14.8 KB
/
schema.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package tfprotov6
import "github.com/hashicorp/terraform-plugin-go/tftypes"
const (
// SchemaNestedBlockNestingModeInvalid indicates that the nesting mode
// for a nested block in the schema is invalid. This generally
// indicates a nested block that was created incorrectly.
SchemaNestedBlockNestingModeInvalid SchemaNestedBlockNestingMode = 0
// SchemaNestedBlockNestingModeSingle indicates that the nested block
// should be treated as a single block with no labels, and there should
// not be more than one of these blocks in the containing block. The
// block will appear in config and state values as a tftypes.Object.
SchemaNestedBlockNestingModeSingle SchemaNestedBlockNestingMode = 1
// SchemaNestedBlockNestingModeList indicates that multiple instances
// of the nested block should be permitted, with no labels, and that
// the instances of the block should appear in config and state values
// as a tftypes.List, with an ElementType of tftypes.Object.
SchemaNestedBlockNestingModeList SchemaNestedBlockNestingMode = 2
// SchemaNestedBlockNestingModeSet indicates that multiple instances
// of the nested block should be permitted, with no labels, and that
// the instances of the block should appear in config and state values
// as a tftypes.Set, with an ElementType of tftypes.Object.
SchemaNestedBlockNestingModeSet SchemaNestedBlockNestingMode = 3
// SchemaNestedBlockNestingModeMap indicates that multiple instances of
// the nested block should be permitted, each with a single label, and
// that they should be represented in state and config values as a
// tftypes.Map, with an ElementType of tftypes.Object. The labels on
// the blocks will be used as the map keys. It is an error, therefore,
// to use the same label value on multiple block instances.
SchemaNestedBlockNestingModeMap SchemaNestedBlockNestingMode = 4
// SchemaNestedBlockNestingModeGroup indicates that the nested block
// should be treated as a single block with no labels, and there should
// not be more than one of these blocks in the containing block. The
// block will appear in config and state values as a tftypes.Object.
//
// SchemaNestedBlockNestingModeGroup is distinct from
// SchemaNestedBlockNestingModeSingle in that it guarantees that the
// block will never be null. If it is omitted from a config, the block
// will still be set, but its attributes and nested blocks will all be
// null. This is an exception to the rule that any block not set in the
// configuration cannot be set in config by the provider; this ensures
// the block is always considered "set" in the configuration, and is
// therefore settable in state by the provider.
SchemaNestedBlockNestingModeGroup SchemaNestedBlockNestingMode = 5
// SchemaObjectNestingModeInvalid indicates that the nesting mode
// for a nested type in the schema is invalid. This generally
// indicates a nested type that was created incorrectly.
SchemaObjectNestingModeInvalid SchemaObjectNestingMode = 0
// SchemaObjectNestingModeSingle indicates that the nested type should
// be treated as a single object. The block will appear in config and state
// values as a tftypes.Object.
SchemaObjectNestingModeSingle SchemaObjectNestingMode = 1
// SchemaObjectNestingModeList indicates that multiple instances of the
// nested type should be permitted, and that the nested type should appear
// in config and state values as a tftypes.List, with an ElementType of
// tftypes.Object.
SchemaObjectNestingModeList SchemaObjectNestingMode = 2
// SchemaObjectNestingModeSet indicates that multiple instances of the
// nested type should be permitted, and that the nested type should appear in
// config and state values as a tftypes.Set, with an ElementType of
// tftypes.Object.
SchemaObjectNestingModeSet SchemaObjectNestingMode = 3
// SchemaObjectNestingModeMap indicates that multiple instances of the
// nested type should be permitted, and that they should be appear in state
// and config values as a tftypes.Map, with an ElementType of
// tftypes.Object.
SchemaObjectNestingModeMap SchemaObjectNestingMode = 4
)
// Schema is how Terraform defines the shape of data. It can be thought of as
// the type information for resources, data sources, provider configuration,
// and all the other data that Terraform sends to providers. It is how
// providers express their requirements for that data.
type Schema struct {
// Version indicates which version of the schema this is. Versions
// should be monotonically incrementing numbers. When Terraform
// encounters a resource stored in state with a schema version lower
// that the schema version the provider advertises for that resource,
// Terraform requests the provider upgrade the resource's state.
Version int64
// Block is the root level of the schema, the collection of attributes
// and blocks that make up a resource, data source, provider, or other
// configuration block.
Block *SchemaBlock
}
// ValueType returns the tftypes.Type for a Schema.
//
// If Schema is missing, an empty Object is returned.
func (s *Schema) ValueType() tftypes.Type {
if s == nil {
return tftypes.Object{
AttributeTypes: map[string]tftypes.Type{},
}
}
return s.Block.ValueType()
}
// SchemaBlock represents a block in a schema. Blocks are how Terraform creates
// groupings of attributes. In configurations, they don't use the equals sign
// and use dynamic instead of list comprehensions.
//
// Blocks will show up in state and config Values as a tftypes.Object, with the
// attributes and nested blocks defining the tftypes.Object's AttributeTypes.
type SchemaBlock struct {
// TODO: why do we have version in the block, too?
Version int64
// Attributes are the attributes defined within the block. These are
// the fields that users can set using the equals sign or reference in
// interpolations.
Attributes []*SchemaAttribute
// BlockTypes are the nested blocks within the block. These are used to
// have blocks within blocks.
BlockTypes []*SchemaNestedBlock
// Description offers an end-user friendly description of what the
// block is for. This will be surfaced to users through editor
// integrations, documentation generation, and other settings.
Description string
// DescriptionKind indicates the formatting and encoding that the
// Description field is using.
DescriptionKind StringKind
// Deprecated, when set to true, indicates that a block should no
// longer be used and users should migrate away from it. At the moment
// it is unused and will have no impact, but it will be used in future
// tooling that is powered by provider schemas to enable richer user
// experiences. Providers should set it when deprecating blocks in
// preparation for these tools.
Deprecated bool
}
// ValueType returns the tftypes.Type for a SchemaBlock.
//
// If SchemaBlock is missing, an empty Object is returned.
func (s *SchemaBlock) ValueType() tftypes.Type {
if s == nil {
return tftypes.Object{
AttributeTypes: map[string]tftypes.Type{},
}
}
attributeTypes := map[string]tftypes.Type{}
for _, attribute := range s.Attributes {
if attribute == nil {
continue
}
attributeType := attribute.ValueType()
if attributeType == nil {
continue
}
attributeTypes[attribute.Name] = attributeType
}
for _, block := range s.BlockTypes {
if block == nil {
continue
}
blockType := block.ValueType()
if blockType == nil {
continue
}
attributeTypes[block.TypeName] = blockType
}
return tftypes.Object{
AttributeTypes: attributeTypes,
}
}
// SchemaAttribute represents a single attribute within a schema block.
// Attributes are the fields users can set in configuration using the equals
// sign, can assign to variables, can interpolate, and can use list
// comprehensions on.
type SchemaAttribute struct {
// Name is the name of the attribute. This is what the user will put
// before the equals sign to assign a value to this attribute.
Name string
// Type indicates the type of data the attribute expects. See the
// documentation for the tftypes package for information on what types
// are supported and their behaviors.
Type tftypes.Type
// NestedType indicates that this is a NestedBlock-style object masquerading
// as an attribute. This field conflicts with Type.
NestedType *SchemaObject
// Description offers an end-user friendly description of what the
// attribute is for. This will be surfaced to users through editor
// integrations, documentation generation, and other settings.
Description string
// Required, when set to true, indicates that this attribute must have
// a value assigned to it by the user or Terraform will throw an error.
Required bool
// Optional, when set to true, indicates that the user does not need to
// supply a value for this attribute, but may.
Optional bool
// Computed, when set to true, indicates the the provider will supply a
// value for this field. If Optional and Required are false and
// Computed is true, the user will not be able to specify a value for
// this field without Terraform throwing an error. If Optional is true
// and Computed is true, the user can specify a value for this field,
// but the provider may supply a value if the user does not. It is
// always a violation of Terraform's protocol to substitute a value for
// what the user entered, even if Computed is true.
Computed bool
// Sensitive, when set to true, indicates that the contents of this
// attribute should be considered sensitive and not included in output.
// This does not encrypt or otherwise protect these values in state, it
// only offers protection from them showing up in plans or other
// output.
Sensitive bool
// DescriptionKind indicates the formatting and encoding that the
// Description field is using.
DescriptionKind StringKind
// Deprecated, when set to true, indicates that a attribute should no
// longer be used and users should migrate away from it. At the moment
// it is unused and will have no impact, but it will be used in future
// tooling that is powered by provider schemas to enable richer user
// experiences. Providers should set it when deprecating attributes in
// preparation for these tools.
Deprecated bool
}
// ValueType returns the tftypes.Type for a SchemaAttribute.
//
// If SchemaAttribute is missing, nil is returned.
func (s *SchemaAttribute) ValueType() tftypes.Type {
if s == nil {
return nil
}
// It is not valid to set both NestedType and Type.
if s.NestedType != nil {
return s.NestedType.ValueType()
}
return s.Type
}
// SchemaNestedBlock is a nested block within another block. See SchemaBlock
// for more information on blocks.
type SchemaNestedBlock struct {
// TypeName is the name of the block. It is what the user will specify
// when using the block in configuration.
TypeName string
// Block is the block being nested inside another block. See the
// SchemaBlock documentation for more information on blocks.
Block *SchemaBlock
// Nesting is the kind of nesting the block is using. Different nesting
// modes have different behaviors and imply different kinds of data.
Nesting SchemaNestedBlockNestingMode
// MinItems is the minimum number of instances of this block that a
// user must specify or Terraform will return an error.
//
// MinItems can only be set for SchemaNestedBlockNestingModeList and
// SchemaNestedBlockNestingModeSet. SchemaNestedBlockNestingModeSingle
// can also set MinItems and MaxItems both to 1 to indicate that the
// block is required to be set. All other SchemaNestedBlockNestingModes
// must leave MinItems set to 0.
MinItems int64
// MaxItems is the maximum number of instances of this block that a
// user may specify before Terraform returns an error.
//
// MaxItems can only be set for SchemaNestedBlockNestingModeList and
// SchemaNestedBlockNestingModeSet. SchemaNestedBlockNestingModeSingle
// can also set MinItems and MaxItems both to 1 to indicate that the
// block is required to be set. All other SchemaNestedBlockNestingModes
// must leave MaxItems set to 0.
MaxItems int64
}
// ValueType returns the tftypes.Type for a SchemaNestedBlock.
//
// If SchemaNestedBlock is missing or the Nesting mode is invalid, nil is
// returned.
func (s *SchemaNestedBlock) ValueType() tftypes.Type {
if s == nil {
return nil
}
blockType := s.Block.ValueType()
switch s.Nesting {
case SchemaNestedBlockNestingModeGroup:
return blockType
case SchemaNestedBlockNestingModeList:
return tftypes.List{
ElementType: blockType,
}
case SchemaNestedBlockNestingModeMap:
return tftypes.Map{
ElementType: blockType,
}
case SchemaNestedBlockNestingModeSet:
return tftypes.Set{
ElementType: blockType,
}
case SchemaNestedBlockNestingModeSingle:
return blockType
default:
return nil
}
}
// SchemaNestedBlockNestingMode indicates the nesting mode for
// SchemaNestedBlocks. The nesting mode determines the number of instances of
// the block allowed, how many labels the block expects, and the data structure
// used for the block in config and state values.
type SchemaNestedBlockNestingMode int32
func (s SchemaNestedBlockNestingMode) String() string {
switch s {
case 0:
return "INVALID"
case 1:
return "SINGLE"
case 2:
return "LIST"
case 3:
return "SET"
case 4:
return "MAP"
case 5:
return "GROUP"
}
return "UNKNOWN"
}
// SchemaObject represents a nested-block-stype object in an Attribute.
type SchemaObject struct {
// Attributes are the attributes defined within the Object.
Attributes []*SchemaAttribute
Nesting SchemaObjectNestingMode
}
// ValueType returns the tftypes.Type for a SchemaObject.
//
// If SchemaObject is missing or the Nesting mode is invalid, nil is returned.
func (s *SchemaObject) ValueType() tftypes.Type {
if s == nil {
return nil
}
attributeTypes := map[string]tftypes.Type{}
for _, attribute := range s.Attributes {
if attribute == nil {
continue
}
attributeType := attribute.ValueType()
if attributeType == nil {
continue
}
attributeTypes[attribute.Name] = attributeType
}
objectType := tftypes.Object{
AttributeTypes: attributeTypes,
}
switch s.Nesting {
case SchemaObjectNestingModeList:
return tftypes.List{
ElementType: objectType,
}
case SchemaObjectNestingModeMap:
return tftypes.Map{
ElementType: objectType,
}
case SchemaObjectNestingModeSet:
return tftypes.Set{
ElementType: objectType,
}
case SchemaObjectNestingModeSingle:
return objectType
default:
return nil
}
}
// SchemaObjectNestingMode indicates the nesting mode for
// SchemaNestedBlocks. The nesting mode determines the number of instances of
// the nested type allowed and the data structure used for the block in config
// and state values.
type SchemaObjectNestingMode int32
func (s SchemaObjectNestingMode) String() string {
switch s {
case 0:
return "INVALID"
case 1:
return "SINGLE"
case 2:
return "LIST"
case 3:
return "SET"
case 4:
return "MAP"
}
return "UNKNOWN"
}