package terraform import ( "fmt" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs/configschema" "github.com/hashicorp/terraform/lang" "github.com/hashicorp/terraform/tfdiags" ) // EvalValidateSelfRef is an EvalNode implementation that checks to ensure that // expressions within a particular referencable block do not reference that // same block. type EvalValidateSelfRef struct { Addr addrs.Referenceable Config hcl.Body ProviderSchema **ProviderSchema } func (n *EvalValidateSelfRef) Eval(ctx EvalContext) tfdiags.Diagnostics { var diags tfdiags.Diagnostics addr := n.Addr addrStrs := make([]string, 0, 1) addrStrs = append(addrStrs, addr.String()) switch tAddr := addr.(type) { case addrs.ResourceInstance: // A resource instance may not refer to its containing resource either. addrStrs = append(addrStrs, tAddr.ContainingResource().String()) } if n.ProviderSchema == nil || *n.ProviderSchema == nil { diags = diags.Append(fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr)) return diags } providerSchema := *n.ProviderSchema var schema *configschema.Block switch tAddr := addr.(type) { case addrs.Resource: schema, _ = providerSchema.SchemaForResourceAddr(tAddr) case addrs.ResourceInstance: schema, _ = providerSchema.SchemaForResourceAddr(tAddr.ContainingResource()) } if schema == nil { diags = diags.Append(fmt.Errorf("no schema available for %s to validate for self-references; this is a bug in Terraform and should be reported", addr)) return diags } refs, _ := lang.ReferencesInBlock(n.Config, schema) for _, ref := range refs { for _, addrStr := range addrStrs { if ref.Subject.String() == addrStr { diags = diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Self-referential block", Detail: fmt.Sprintf("Configuration for %s may not refer to itself.", addrStr), Subject: ref.SourceRange.ToHCL().Ptr(), }) } } } return diags }