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