github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/configs/module_merge.go (about) 1 package configs 2 3 import ( 4 "fmt" 5 6 "github.com/muratcelep/terraform/not-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 (v *Variable) merge(ov *Variable) hcl.Diagnostics { 39 var diags hcl.Diagnostics 40 41 if ov.DescriptionSet { 42 v.Description = ov.Description 43 v.DescriptionSet = ov.DescriptionSet 44 } 45 if ov.SensitiveSet { 46 v.Sensitive = ov.Sensitive 47 v.SensitiveSet = ov.SensitiveSet 48 } 49 if ov.Default != cty.NilVal { 50 v.Default = ov.Default 51 } 52 if ov.Type != cty.NilType { 53 v.Type = ov.Type 54 v.ConstraintType = ov.ConstraintType 55 } 56 if ov.ParsingMode != 0 { 57 v.ParsingMode = ov.ParsingMode 58 } 59 if ov.NullableSet { 60 v.Nullable = ov.Nullable 61 v.NullableSet = ov.NullableSet 62 } 63 64 // If the override file overrode type without default or vice-versa then 65 // it may have created an invalid situation, which we'll catch now by 66 // attempting to re-convert the value. 67 // 68 // Note that here we may be re-converting an already-converted base value 69 // from the base config. This will be a no-op if the type was not changed, 70 // but in particular might be user-observable in the edge case where the 71 // literal value in config could've been converted to the overridden type 72 // constraint but the converted value cannot. In practice, this situation 73 // should be rare since most of our conversions are interchangable. 74 if v.Default != cty.NilVal { 75 val, err := convert.Convert(v.Default, v.ConstraintType) 76 if err != nil { 77 // What exactly we'll say in the error message here depends on whether 78 // it was Default or Type that was overridden here. 79 switch { 80 case ov.Type != cty.NilType && ov.Default == cty.NilVal: 81 // If only the type was overridden 82 diags = append(diags, &hcl.Diagnostic{ 83 Severity: hcl.DiagError, 84 Summary: "Invalid default value for variable", 85 Detail: fmt.Sprintf("Overriding this variable's type constraint has made its default value invalid: %s.", err), 86 Subject: &ov.DeclRange, 87 }) 88 case ov.Type == cty.NilType && ov.Default != cty.NilVal: 89 // Only the default was overridden 90 diags = append(diags, &hcl.Diagnostic{ 91 Severity: hcl.DiagError, 92 Summary: "Invalid default value for variable", 93 Detail: fmt.Sprintf("The overridden default value for this variable is not compatible with the variable's type constraint: %s.", err), 94 Subject: &ov.DeclRange, 95 }) 96 default: 97 diags = append(diags, &hcl.Diagnostic{ 98 Severity: hcl.DiagError, 99 Summary: "Invalid default value for variable", 100 Detail: fmt.Sprintf("This variable's default value is not compatible with its type constraint: %s.", err), 101 Subject: &ov.DeclRange, 102 }) 103 } 104 } else { 105 v.Default = val 106 } 107 108 // ensure a null default wasn't merged in when it is not allowed 109 if !v.Nullable && v.Default.IsNull() { 110 diags = append(diags, &hcl.Diagnostic{ 111 Severity: hcl.DiagError, 112 Summary: "Invalid default value for variable", 113 Detail: "A null default value is not valid when nullable=false.", 114 Subject: &ov.DeclRange, 115 }) 116 } 117 } 118 119 return diags 120 } 121 122 func (l *Local) merge(ol *Local) hcl.Diagnostics { 123 var diags hcl.Diagnostics 124 125 // Since a local is just a single expression in configuration, the 126 // override definition entirely replaces the base definition, including 127 // the source range so that we'll send the user to the right place if 128 // there is an error. 129 l.Expr = ol.Expr 130 l.DeclRange = ol.DeclRange 131 132 return diags 133 } 134 135 func (o *Output) merge(oo *Output) hcl.Diagnostics { 136 var diags hcl.Diagnostics 137 138 if oo.Description != "" { 139 o.Description = oo.Description 140 } 141 if oo.Expr != nil { 142 o.Expr = oo.Expr 143 } 144 if oo.SensitiveSet { 145 o.Sensitive = oo.Sensitive 146 o.SensitiveSet = oo.SensitiveSet 147 } 148 149 // We don't allow depends_on to be overridden because that is likely to 150 // cause confusing misbehavior. 151 if len(oo.DependsOn) != 0 { 152 diags = append(diags, &hcl.Diagnostic{ 153 Severity: hcl.DiagError, 154 Summary: "Unsupported override", 155 Detail: "The depends_on argument may not be overridden.", 156 Subject: oo.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 157 }) 158 } 159 160 return diags 161 } 162 163 func (mc *ModuleCall) merge(omc *ModuleCall) hcl.Diagnostics { 164 var diags hcl.Diagnostics 165 166 if omc.SourceSet { 167 mc.SourceAddr = omc.SourceAddr 168 mc.SourceAddrRaw = omc.SourceAddrRaw 169 mc.SourceAddrRange = omc.SourceAddrRange 170 mc.SourceSet = omc.SourceSet 171 } 172 173 if omc.Count != nil { 174 mc.Count = omc.Count 175 } 176 177 if omc.ForEach != nil { 178 mc.ForEach = omc.ForEach 179 } 180 181 if len(omc.Version.Required) != 0 { 182 mc.Version = omc.Version 183 } 184 185 mc.Config = MergeBodies(mc.Config, omc.Config) 186 187 if len(omc.Providers) != 0 { 188 mc.Providers = omc.Providers 189 } 190 191 // We don't allow depends_on to be overridden because that is likely to 192 // cause confusing misbehavior. 193 if len(mc.DependsOn) != 0 { 194 diags = append(diags, &hcl.Diagnostic{ 195 Severity: hcl.DiagError, 196 Summary: "Unsupported override", 197 Detail: "The depends_on argument may not be overridden.", 198 Subject: mc.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 199 }) 200 } 201 202 return diags 203 } 204 205 func (r *Resource) merge(or *Resource, rps map[string]*RequiredProvider) hcl.Diagnostics { 206 var diags hcl.Diagnostics 207 208 if r.Mode != or.Mode { 209 // This is always a programming error, since managed and data resources 210 // are kept in separate maps in the configuration structures. 211 panic(fmt.Errorf("can't merge %s into %s", or.Mode, r.Mode)) 212 } 213 214 if or.Count != nil { 215 r.Count = or.Count 216 } 217 if or.ForEach != nil { 218 r.ForEach = or.ForEach 219 } 220 221 if or.ProviderConfigRef != nil { 222 r.ProviderConfigRef = or.ProviderConfigRef 223 if existing, exists := rps[or.ProviderConfigRef.Name]; exists { 224 r.Provider = existing.Type 225 } else { 226 r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.ProviderConfigRef.Name) 227 } 228 } 229 230 // Provider FQN is set by Terraform during Merge 231 232 if r.Mode == addrs.ManagedResourceMode { 233 // or.Managed is always non-nil for managed resource mode 234 235 if or.Managed.Connection != nil { 236 r.Managed.Connection = or.Managed.Connection 237 } 238 if or.Managed.CreateBeforeDestroySet { 239 r.Managed.CreateBeforeDestroy = or.Managed.CreateBeforeDestroy 240 r.Managed.CreateBeforeDestroySet = or.Managed.CreateBeforeDestroySet 241 } 242 if len(or.Managed.IgnoreChanges) != 0 { 243 r.Managed.IgnoreChanges = or.Managed.IgnoreChanges 244 } 245 if or.Managed.IgnoreAllChanges { 246 r.Managed.IgnoreAllChanges = true 247 } 248 if or.Managed.PreventDestroySet { 249 r.Managed.PreventDestroy = or.Managed.PreventDestroy 250 r.Managed.PreventDestroySet = or.Managed.PreventDestroySet 251 } 252 if len(or.Managed.Provisioners) != 0 { 253 r.Managed.Provisioners = or.Managed.Provisioners 254 } 255 } 256 257 r.Config = MergeBodies(r.Config, or.Config) 258 259 // We don't allow depends_on to be overridden because that is likely to 260 // cause confusing misbehavior. 261 if len(or.DependsOn) != 0 { 262 diags = append(diags, &hcl.Diagnostic{ 263 Severity: hcl.DiagError, 264 Summary: "Unsupported override", 265 Detail: "The depends_on argument may not be overridden.", 266 Subject: or.DependsOn[0].SourceRange().Ptr(), // the first item is the closest range we have 267 }) 268 } 269 270 return diags 271 }