github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/eval_validate_selfref.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  
     8  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs/configschema"
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/lang"
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
    12  )
    13  
    14  // EvalValidateSelfRef is an EvalNode implementation that checks to ensure that
    15  // expressions within a particular referencable block do not reference that
    16  // same block.
    17  type EvalValidateSelfRef struct {
    18  	Addr           addrs.Referenceable
    19  	Config         hcl.Body
    20  	ProviderSchema **ProviderSchema
    21  }
    22  
    23  func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
    24  	var diags tfdiags.Diagnostics
    25  	addr := n.Addr
    26  
    27  	addrStrs := make([]string, 0, 1)
    28  	addrStrs = append(addrStrs, addr.String())
    29  	switch tAddr := addr.(type) {
    30  	case addrs.ResourceInstance:
    31  		// A resource instance may not refer to its containing resource either.
    32  		addrStrs = append(addrStrs, tAddr.ContainingResource().String())
    33  	}
    34  
    35  	if n.ProviderSchema == nil || *n.ProviderSchema == nil {
    36  		return nil, fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr)
    37  	}
    38  
    39  	providerSchema := *n.ProviderSchema
    40  	var schema *configschema.Block
    41  	switch tAddr := addr.(type) {
    42  	case addrs.Resource:
    43  		schema, _ = providerSchema.SchemaForResourceAddr(tAddr)
    44  	case addrs.ResourceInstance:
    45  		schema, _ = providerSchema.SchemaForResourceAddr(tAddr.ContainingResource())
    46  	}
    47  
    48  	if schema == nil {
    49  		return nil, fmt.Errorf("no schema available for %s to validate for self-references; this is a bug in Terraform and should be reported", addr)
    50  	}
    51  
    52  	refs, _ := lang.ReferencesInBlock(n.Config, schema)
    53  	for _, ref := range refs {
    54  		for _, addrStr := range addrStrs {
    55  			if ref.Subject.String() == addrStr {
    56  				diags = diags.Append(&hcl.Diagnostic{
    57  					Severity: hcl.DiagError,
    58  					Summary:  "Self-referential block",
    59  					Detail:   fmt.Sprintf("Configuration for %s may not refer to itself.", addrStr),
    60  					Subject:  ref.SourceRange.ToHCL().Ptr(),
    61  				})
    62  			}
    63  		}
    64  	}
    65  
    66  	return nil, diags.NonFatalErr()
    67  }