check resource-level connections block for refs

References from a resource-level connection blocks were not returned
from NodeAbstractResource.References, causing the provisioner connection
attributes to sometimes be evaluated too early.
This commit is contained in:
James Bardin 2019-12-12 12:47:08 -05:00
parent 9efab422ba
commit a57337327d
4 changed files with 80 additions and 1 deletions

View File

@ -11131,6 +11131,63 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
} }
} }
func TestContext2Apply_plannedConnectionRefs(t *testing.T) {
m := testModule(t, "apply-plan-connection-refs")
p := testProvider("test")
p.DiffFn = testDiffFn
p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
s := req.PlannedState.AsValueMap()
// delay "a" slightly, so if the reference edge is missing the "b"
// provisioner will see an unknown value.
if s["foo"].AsString() == "a" {
time.Sleep(500 * time.Millisecond)
}
s["id"] = cty.StringVal("ID")
resp.NewState = cty.ObjectVal(s)
return resp
}
pr := testProvisioner()
pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
host := req.Connection.GetAttr("host")
if host.IsNull() || !host.IsKnown() {
resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host))
}
return resp
}
providerResolver := providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("test"): testProviderFuncFixed(p),
},
)
provisioners := map[string]ProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
}
hook := &testHook{}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providerResolver,
Provisioners: provisioners,
Hooks: []Hook{hook},
})
_, diags := ctx.Plan()
diags.HasErrors()
if diags.HasErrors() {
t.Fatalf("diags: %s", diags.Err())
}
_, diags = ctx.Apply()
if diags.HasErrors() {
t.Fatalf("diags: %s", diags.Err())
}
}
func TestContext2Apply_cbdCycle(t *testing.T) { func TestContext2Apply_cbdCycle(t *testing.T) {
m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle") m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle")
p := testProvider("test") p := testProvider("test")

View File

@ -195,6 +195,11 @@ func (n *NodeAbstractResource) References() []*addrs.Reference {
refs, _ = lang.ReferencesInBlock(c.Config, n.Schema) refs, _ = lang.ReferencesInBlock(c.Config, n.Schema)
result = append(result, refs...) result = append(result, refs...)
if c.Managed != nil { if c.Managed != nil {
if c.Managed.Connection != nil {
refs, _ = lang.ReferencesInBlock(c.Managed.Connection.Config, connectionBlockSupersetSchema)
result = append(result, refs...)
}
for _, p := range c.Managed.Provisioners { for _, p := range c.Managed.Provisioners {
if p.When != configs.ProvisionerWhenCreate { if p.When != configs.ProvisionerWhenCreate {
continue continue

View File

@ -120,7 +120,6 @@ func (p *MockProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequ
} }
if p.ProvisionResourceFn != nil { if p.ProvisionResourceFn != nil {
fn := p.ProvisionResourceFn fn := p.ProvisionResourceFn
p.Unlock()
return fn(r) return fn(r)
} }

View File

@ -0,0 +1,18 @@
variable "msg" {
default = "ok"
}
resource "test_instance" "a" {
foo = "a"
}
resource "test_instance" "b" {
foo = "b"
provisioner "shell" {
command = "echo ${var.msg}"
}
connection {
host = test_instance.a.id
}
}