core: Pass ProviderSchema to EvalValidateSelfRef

EvalValidateSelfRef needs schema in order to extract references. It was
previously expecting a *configschema.Block directly, but we weren't
actually passing that in from anywhere except the tests because it's not
available directly in that form during the evaltree for
node_resource_validate.

Instead, we now pass in the whole *ProviderSchema for the associated
provider and have this EvalNode find the schema itself based on the
address. This breaks some of the generality of this node (now only really
works for resource addresses) but that's okay since we have no other
use-case right now anyway.
This commit is contained in:
Martin Atkins 2018-05-11 16:17:06 -07:00
parent 54464e3f93
commit b031e18332
4 changed files with 54 additions and 21 deletions

View File

@ -887,7 +887,7 @@ func TestContext2Validate_selfRefMulti(t *testing.T) {
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.List(cty.String), Optional: true},
"foo": {Type: cty.String, Optional: true},
},
},
},

View File

@ -3,22 +3,21 @@ package terraform
import (
"fmt"
"github.com/hashicorp/terraform/tfdiags"
"github.com/hashicorp/terraform/lang"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/config/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
Schema *configschema.Block
Addr addrs.Referenceable
Config hcl.Body
ProviderSchema **ProviderSchema
}
func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
@ -33,7 +32,34 @@ func (n *EvalValidateSelfRef) Eval(ctx EvalContext) (interface{}, error) {
addrStrs = append(addrStrs, tAddr.ContainingResource().String())
}
refs, _ := lang.ReferencesInBlock(n.Config, n.Schema)
if n.ProviderSchema == nil || *n.ProviderSchema == nil {
return nil, fmt.Errorf("provider schema unavailable while validating %s for self-references; this is a bug in Terraform and should be reported", addr)
}
providerSchema := *n.ProviderSchema
var schema *configschema.Block
switch tAddr := addr.(type) {
case addrs.Resource:
switch tAddr.Mode {
case addrs.ManagedResourceMode:
schema = providerSchema.ResourceTypes[tAddr.Type]
case addrs.DataResourceMode:
schema = providerSchema.DataSources[tAddr.Type]
}
case addrs.ResourceInstance:
switch tAddr.Resource.Mode {
case addrs.ManagedResourceMode:
schema = providerSchema.ResourceTypes[tAddr.Resource.Type]
case addrs.DataResourceMode:
schema = providerSchema.DataSources[tAddr.Resource.Type]
}
}
if schema == nil {
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)
}
refs, _ := lang.ReferencesInBlock(n.Config, schema)
for _, ref := range refs {
for _, addrStr := range addrStrs {
if ref.Subject.String() == addrStr {

View File

@ -80,18 +80,24 @@ func TestEvalValidateSelfRef(t *testing.T) {
},
})
n := &EvalValidateSelfRef{
Addr: test.Addr,
Config: body,
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {
Type: cty.String,
Required: true,
ps := &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {
Type: cty.String,
Required: true,
},
},
},
},
}
n := &EvalValidateSelfRef{
Addr: test.Addr,
Config: body,
ProviderSchema: &ps,
}
result, err := n.Eval(nil)
if result != nil {
t.Fatal("result should always be nil")

View File

@ -124,15 +124,16 @@ func (n *NodeValidatableResourceInstance) EvalTree() EvalNode {
seq := &EvalSequence{
Nodes: []EvalNode{
&EvalValidateSelfRef{
Addr: addr.Resource,
Config: config.Config,
},
&EvalGetProvider{
Addr: n.ResolvedProvider,
Output: &provider,
Schema: &providerSchema,
},
&EvalValidateSelfRef{
Addr: addr.Resource,
Config: config.Config,
ProviderSchema: &providerSchema,
},
&EvalValidateResource{
Addr: addr.Resource,
Provider: &provider,