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 }