terraform: self-referencing variables in provisoiners work

This commit is contained in:
Mitchell Hashimoto 2014-07-24 07:58:45 -07:00
parent 945f41d192
commit 1ee69761d4
5 changed files with 89 additions and 16 deletions

View File

@ -567,6 +567,16 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
} }
} }
// Update the resulting diff
c.sl.Lock()
if rs.ID == "" {
delete(c.state.Resources, r.Id)
delete(c.state.Tainted, r.Id)
} else {
c.state.Resources[r.Id] = rs
}
c.sl.Unlock()
// Invoke any provisioners we have defined. This is only done // Invoke any provisioners we have defined. This is only done
// if the resource was created, as updates or deletes do not // if the resource was created, as updates or deletes do not
// invoke provisioners. // invoke provisioners.
@ -581,18 +591,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
} }
} }
// Update the resulting diff if tainted {
c.sl.Lock() c.sl.Lock()
if rs.ID == "" { c.state.Tainted[r.Id] = struct{}{}
delete(c.state.Resources, r.Id) c.sl.Unlock()
} else {
c.state.Resources[r.Id] = rs
if tainted {
c.state.Tainted[r.Id] = struct{}{}
}
} }
c.sl.Unlock()
// Update the state for the resource itself // Update the state for the resource itself
r.State = rs r.State = rs

View File

@ -550,6 +550,52 @@ func TestContextApply_provisionerFail(t *testing.T) {
} }
} }
func TestContextApply_provisionerResourceRef(t *testing.T) {
c := testConfig(t, "apply-provisioner-resource-ref")
p := testProvider("aws")
pr := testProvisioner()
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error {
val, ok := c.Config["foo"]
if !ok || val != "2" {
t.Fatalf("bad value for foo: %v %#v", val, c)
}
return nil
}
ctx := testContext(t, &ContextOpts{
Config: c,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
Provisioners: map[string]ResourceProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
})
if _, err := ctx.Plan(nil); err != nil {
t.Fatalf("err: %s", err)
}
state, err := ctx.Apply()
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
// Verify apply was invoked
if !pr.ApplyCalled {
t.Fatalf("provisioner not invoked")
}
}
func TestContextApply_outputDiffVars(t *testing.T) { func TestContextApply_outputDiffVars(t *testing.T) {
c := testConfig(t, "apply-good") c := testConfig(t, "apply-good")
p := testProvider("aws") p := testProvider("aws")

View File

@ -611,20 +611,20 @@ func graphAddVariableDeps(g *depgraph.Graph) {
// Handle the resource variables // Handle the resource variables
vars = m.Config.RawConfig.Variables vars = m.Config.RawConfig.Variables
nounAddVariableDeps(g, n, vars) nounAddVariableDeps(g, n, vars, false)
// Handle the variables of the resource provisioners // Handle the variables of the resource provisioners
for _, p := range m.Resource.Provisioners { for _, p := range m.Resource.Provisioners {
vars = p.RawConfig.Variables vars = p.RawConfig.Variables
nounAddVariableDeps(g, n, vars) nounAddVariableDeps(g, n, vars, true)
vars = p.ConnInfo.Variables vars = p.ConnInfo.Variables
nounAddVariableDeps(g, n, vars) nounAddVariableDeps(g, n, vars, true)
} }
case *GraphNodeResourceProvider: case *GraphNodeResourceProvider:
vars = m.Config.RawConfig.Variables vars = m.Config.RawConfig.Variables
nounAddVariableDeps(g, n, vars) nounAddVariableDeps(g, n, vars, false)
default: default:
continue continue
@ -634,7 +634,11 @@ func graphAddVariableDeps(g *depgraph.Graph) {
// nounAddVariableDeps updates the dependencies of a noun given // nounAddVariableDeps updates the dependencies of a noun given
// a set of associated variable values // a set of associated variable values
func nounAddVariableDeps(g *depgraph.Graph, n *depgraph.Noun, vars map[string]config.InterpolatedVariable) { func nounAddVariableDeps(
g *depgraph.Graph,
n *depgraph.Noun,
vars map[string]config.InterpolatedVariable,
removeSelf bool) {
for _, v := range vars { for _, v := range vars {
// Only resource variables impose dependencies // Only resource variables impose dependencies
rv, ok := v.(*config.ResourceVariable) rv, ok := v.(*config.ResourceVariable)
@ -648,6 +652,12 @@ func nounAddVariableDeps(g *depgraph.Graph, n *depgraph.Noun, vars map[string]co
continue continue
} }
// If we're ignoring self-references, then don't add that
// dependency.
if removeSelf && n == target {
continue
}
// Build the dependency // Build the dependency
dep := &depgraph.Dependency{ dep := &depgraph.Dependency{
Name: rv.ResourceId(), Name: rv.ResourceId(),

View File

@ -139,6 +139,13 @@ aws_instance.foo:
type = aws_instance type = aws_instance
` `
const testTerraformApplyProvisionerResourceRefStr = `
aws_instance.bar:
ID = foo
num = 2
type = aws_instance
`
const testTerraformApplyDestroyStr = ` const testTerraformApplyDestroyStr = `
<no state> <no state>
` `

View File

@ -0,0 +1,7 @@
resource "aws_instance" "bar" {
num = "2"
provisioner "shell" {
foo = "${aws_instance.bar.num}"
}
}