github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/configs/module_merge.go (about)

     1  package configs
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform/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(omc.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:  omc.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  }