github.com/rvichery/terraform@v0.11.10/configs/module_merge.go (about) 1 package configs 2 3 import ( 4 "fmt" 5 6 "github.com/hashicorp/hcl2/hcl" 7 "github.com/zclconf/go-cty/cty" 8 "github.com/zclconf/go-cty/cty/convert" 9 ) 10 11 // The methods in this file are used by Module.mergeFile to apply overrides 12 // to our different configuration elements. These methods all follow the 13 // pattern of mutating the receiver to incorporate settings from the parameter, 14 // returning error diagnostics if any aspect of the parameter cannot be merged 15 // into the receiver for some reason. 16 // 17 // User expectation is that anything _explicitly_ set in the given object 18 // should take precedence over the corresponding settings in the receiver, 19 // but that anything omitted in the given object should be left unchanged. 20 // In some cases it may be reasonable to do a "deep merge" of certain nested 21 // features, if it is possible to unambiguously correlate the nested elements 22 // and their behaviors are orthogonal to each other. 23 24 func (p *Provider) merge(op *Provider) hcl.Diagnostics { 25 var diags hcl.Diagnostics 26 27 if op.Version.Required != nil { 28 p.Version = op.Version 29 } 30 31 p.Config = mergeBodies(p.Config, op.Config) 32 33 return diags 34 } 35 36 func mergeProviderVersionConstraints(recv map[string][]VersionConstraint, ovrd []*ProviderRequirement) { 37 // Any provider name that's mentioned in the override gets nilled out in 38 // our map so that we'll rebuild it below. Any provider not mentioned is 39 // left unchanged. 40 for _, reqd := range ovrd { 41 delete(recv, reqd.Name) 42 } 43 for _, reqd := range ovrd { 44 recv[reqd.Name] = append(recv[reqd.Name], reqd.Requirement) 45 } 46 } 47 48 func (v *Variable) merge(ov *Variable) hcl.Diagnostics { 49 var diags hcl.Diagnostics 50 51 if ov.DescriptionSet { 52 v.Description = ov.Description 53 v.DescriptionSet = ov.DescriptionSet 54 } 55 if ov.Default != cty.NilVal { 56 v.Default = ov.Default 57 } 58 if ov.Type != cty.NilType { 59 v.Type = ov.Type 60 } 61 if ov.ParsingMode != 0 { 62 v.ParsingMode = ov.ParsingMode 63 } 64 65 // If the override file overrode type without default or vice-versa then 66 // it may have created an invalid situation, which we'll catch now by 67 // attempting to re-convert the value. 68 // 69 // Note that here we may be re-converting an already-converted base value 70 // from the base config. This will be a no-op if the type was not changed, 71 // but in particular might be user-observable in the edge case where the 72 // literal value in config could've been converted to the overridden type 73 // constraint but the converted value cannot. In practice, this situation 74 // should be rare since most of our conversions are interchangable. 75 if v.Default != cty.NilVal { 76 val, err := convert.Convert(v.Default, v.Type) 77 if err != nil { 78 // What exactly we'll say in the error message here depends on whether 79 // it was Default or Type that was overridden here. 80 switch { 81 case ov.Type != cty.NilType && ov.Default == cty.NilVal: 82 // If only the type was overridden 83 diags = append(diags, &hcl.Diagnostic{ 84 Severity: hcl.DiagError, 85 Summary: "Invalid default value for variable", 86 Detail: fmt.Sprintf("Overriding this variable's type constraint has made its default value invalid: %s.", err), 87 Subject: &ov.DeclRange, 88 }) 89 case ov.Type == cty.NilType && ov.Default != cty.NilVal: 90 // Only the default was overridden 91 diags = append(diags, &hcl.Diagnostic{ 92 Severity: hcl.DiagError, 93 Summary: "Invalid default value for variable", 94 Detail: fmt.Sprintf("The overridden default value for this variable is not compatible with the variable's type constraint: %s.", err), 95 Subject: &ov.DeclRange, 96 }) 97 default: 98 diags = append(diags, &hcl.Diagnostic{ 99 Severity: hcl.DiagError, 100 Summary: "Invalid default value for variable", 101 Detail: fmt.Sprintf("This variable's default value is not compatible with its type constraint: %s.", err), 102 Subject: &ov.DeclRange, 103 }) 104 } 105 } else { 106 v.Default = val 107 } 108 } 109 110 return diags 111 } 112 113 func (l *Local) merge(ol *Local) hcl.Diagnostics { 114 var diags hcl.Diagnostics 115 116 // Since a local is just a single expression in configuration, the 117 // override definition entirely replaces the base definition, including 118 // the source range so that we'll send the user to the right place if 119 // there is an error. 120 l.Expr = ol.Expr 121 l.DeclRange = ol.DeclRange 122 123 return diags 124 } 125 126 func (o *Output) merge(oo *Output) hcl.Diagnostics { 127 var diags hcl.Diagnostics 128 129 if oo.Description != "" { 130 o.Description = oo.Description 131 } 132 if oo.Expr != nil { 133 o.Expr = oo.Expr 134 } 135 if oo.SensitiveSet { 136 o.Sensitive = oo.Sensitive 137 o.SensitiveSet = oo.SensitiveSet 138 } 139 140 // We don't allow depends_on to be overridden because that is likely to 141 // cause confusing misbehavior. 142 if len(oo.DependsOn) != 0 { 143 diags = append(diags, &hcl.Diagnostic{ 144 Severity: hcl.DiagError, 145 Summary: "Unsupported override", 146 Detail: "The depends_on argument may not be overridden.", 147 Subject: oo.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 148 }) 149 } 150 151 return diags 152 } 153 154 func (mc *ModuleCall) merge(omc *ModuleCall) hcl.Diagnostics { 155 var diags hcl.Diagnostics 156 157 if omc.SourceSet { 158 mc.SourceAddr = omc.SourceAddr 159 mc.SourceAddrRange = omc.SourceAddrRange 160 mc.SourceSet = omc.SourceSet 161 } 162 163 if omc.Count != nil { 164 mc.Count = omc.Count 165 } 166 167 if omc.ForEach != nil { 168 mc.ForEach = omc.ForEach 169 } 170 171 if len(omc.Version.Required) != 0 { 172 mc.Version = omc.Version 173 } 174 175 mc.Config = mergeBodies(mc.Config, omc.Config) 176 177 // We don't allow depends_on to be overridden because that is likely to 178 // cause confusing misbehavior. 179 if len(mc.DependsOn) != 0 { 180 diags = append(diags, &hcl.Diagnostic{ 181 Severity: hcl.DiagError, 182 Summary: "Unsupported override", 183 Detail: "The depends_on argument may not be overridden.", 184 Subject: mc.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 185 }) 186 } 187 188 return diags 189 } 190 191 func (r *ManagedResource) merge(or *ManagedResource) hcl.Diagnostics { 192 var diags hcl.Diagnostics 193 194 if or.Connection != nil { 195 r.Connection = or.Connection 196 } 197 if or.Count != nil { 198 r.Count = or.Count 199 } 200 if or.CreateBeforeDestroySet { 201 r.CreateBeforeDestroy = or.CreateBeforeDestroy 202 r.CreateBeforeDestroySet = or.CreateBeforeDestroySet 203 } 204 if or.ForEach != nil { 205 r.ForEach = or.ForEach 206 } 207 if len(or.IgnoreChanges) != 0 { 208 r.IgnoreChanges = or.IgnoreChanges 209 } 210 if or.PreventDestroySet { 211 r.PreventDestroy = or.PreventDestroy 212 r.PreventDestroySet = or.PreventDestroySet 213 } 214 if or.ProviderConfigRef != nil { 215 r.ProviderConfigRef = or.ProviderConfigRef 216 } 217 if len(or.Provisioners) != 0 { 218 r.Provisioners = or.Provisioners 219 } 220 221 r.Config = mergeBodies(r.Config, or.Config) 222 223 // We don't allow depends_on to be overridden because that is likely to 224 // cause confusing misbehavior. 225 if len(r.DependsOn) != 0 { 226 diags = append(diags, &hcl.Diagnostic{ 227 Severity: hcl.DiagError, 228 Summary: "Unsupported override", 229 Detail: "The depends_on argument may not be overridden.", 230 Subject: r.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 231 }) 232 } 233 234 return diags 235 } 236 237 func (r *DataResource) merge(or *DataResource) hcl.Diagnostics { 238 var diags hcl.Diagnostics 239 240 if or.Count != nil { 241 r.Count = or.Count 242 } 243 if or.ForEach != nil { 244 r.ForEach = or.ForEach 245 } 246 if or.ProviderConfigRef != nil { 247 r.ProviderConfigRef = or.ProviderConfigRef 248 } 249 250 r.Config = mergeBodies(r.Config, or.Config) 251 252 // We don't allow depends_on to be overridden because that is likely to 253 // cause confusing misbehavior. 254 if len(r.DependsOn) != 0 { 255 diags = append(diags, &hcl.Diagnostic{ 256 Severity: hcl.DiagError, 257 Summary: "Unsupported override", 258 Detail: "The depends_on argument may not be overridden.", 259 Subject: r.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 260 }) 261 } 262 263 return diags 264 }