-
Notifications
You must be signed in to change notification settings - Fork 107
/
hcl_block.go
141 lines (116 loc) · 3.64 KB
/
hcl_block.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
package main
import (
"github.com/sl1pm4t/k2tf/pkg/tfkschema"
"strings"
"github.com/hashicorp/hcl/v2/hclwrite"
log "github.com/sirupsen/logrus"
"github.com/zclconf/go-cty/cty"
)
// hclBlock is a wrapper for hclwrite.Block that allows tagging some extra
// metadata to each block.
type hclBlock struct {
//
name string
//
fieldName string
// The parent hclBlock to this hclBlock
parent *hclBlock
// The wrapped HCL block
hcl *hclwrite.Block
// hasValue means a child field of this block had a non-nil / non-zero value.
// If this is false when closeBlock() is called, the block won't be appended to
// parent
hasValue bool
// inlined flags whether this block is "transparent" Some Structs in the
// Kubernetes API structure are marked as "inline", meaning they don't create
// a new block, and their child value is propagated up the hierarchy.
// See v1.Volume as an example
inlined bool
// inlined flags whether this block is supported in the Terraform Provider schema
// Unsupported blocks will be excluded from HCL rendering
unsupported bool
// isMap flags whether the output of this block will be map syntax rather than a sub-block
// e.g.
// mapName = {
// key = "value"
// }
// vs.
// mapName {
// key = "value"
// }
// In TF0.12.0 Schema attributes of type schema.TypeMap must be written with the former syntax, and sub-blocks
// most use the latter.
// However, there are some cases where a Golang map on the Kubernetes object side is not defined
// as schema.TypeMap on the Terraform side (e.g. Container.Limits) so isMap is used to track how this block
// should be outputted.
isMap bool
hclMap map[string]cty.Value
}
// A child block is adding a sub-block, write HCL to:
// - this hclBlock's hcl Body if this block is not inlined
// - parent's HCL body if this block is "inlined"
func (b *hclBlock) AppendBlock(hcl *hclwrite.Block) {
if b.inlined {
// append to parent
b.parent.AppendBlock(hcl)
} else {
b.hcl.Body().AppendBlock(hcl)
}
}
// A child block is adding an attribute, write HCL to:
// - this hclBlock's hcl Body if this block is not inlined
// - parent's HCL body if this block is "inlined"
func (b *hclBlock) SetAttributeValue(name string, val cty.Value) {
if b.isMap {
if b.hclMap == nil {
b.hclMap = map[string]cty.Value{name: val}
} else {
b.hclMap[name] = val
}
} else if includeUnsupported || tfkschema.IsAttributeSupported(b.FullSchemaName()+"."+name) {
if b.inlined {
// append to parent
b.parent.SetAttributeValue(name, val)
} else {
b.hcl.Body().SetAttributeValue(name, val)
}
} else {
log.Debugf("skipping attribute: %s - not supported by provider", name)
}
}
func (b *hclBlock) FullSchemaName() string {
parentName := ""
if b.parent != nil {
parentName = b.parent.FullSchemaName()
}
if b.inlined {
return parentName
}
return strings.TrimLeft(parentName+"."+b.name, ".")
}
func (b *hclBlock) isSupportedAttribute() bool {
return tfkschema.IsAttributeSupported(b.FullSchemaName())
}
func (b *hclBlock) isRequired() bool {
if b.parent == nil {
// top level resource block is always required.
return true
}
required := tfkschema.IsAttributeRequired(b.FullSchemaName())
if required && !b.hasValue && !b.parent.isRequired() {
// If current attribute has no value, only flag as required if parent(s) are also required.
// This is to match how Terraform handles the Required flag of nested attributes.
required = false
}
return required
}
func (b *hclBlock) FullFieldName() string {
parentName := ""
if b.parent != nil {
parentName = b.parent.FullFieldName()
}
if b.inlined {
return parentName
}
return strings.TrimLeft(parentName+"."+b.fieldName, ".")
}