terraform: count.index

This commit is contained in:
Mitchell Hashimoto 2014-10-02 22:02:59 -07:00
parent 2e63a69e57
commit ea18b62e8f
7 changed files with 69 additions and 15 deletions

View File

@ -498,7 +498,7 @@ func (c *walkContext) Walk() error {
outputs := make(map[string]string) outputs := make(map[string]string)
for _, o := range conf.Outputs { for _, o := range conf.Outputs {
if err := c.computeVars(o.RawConfig); err != nil { if err := c.computeVars(o.RawConfig, nil); err != nil {
return err return err
} }
vraw := o.RawConfig.Config()["value"] vraw := o.RawConfig.Config()["value"]
@ -619,7 +619,7 @@ func (c *walkContext) applyWalkFn() depgraph.WalkFunc {
if !diff.Destroy { if !diff.Destroy {
// Since we need the configuration, interpolate the variables // Since we need the configuration, interpolate the variables
if err := r.Config.interpolate(c); err != nil { if err := r.Config.interpolate(c, r); err != nil {
return err return err
} }
@ -780,7 +780,7 @@ func (c *walkContext) planWalkFn() depgraph.WalkFunc {
diff = &InstanceDiff{Destroy: true} diff = &InstanceDiff{Destroy: true}
} else { } else {
// Make sure the configuration is interpolated // Make sure the configuration is interpolated
if err := r.Config.interpolate(c); err != nil { if err := r.Config.interpolate(c, r); err != nil {
return err return err
} }
@ -993,7 +993,7 @@ func (c *walkContext) validateWalkFn() depgraph.WalkFunc {
if rn.ExpandMode > ResourceExpandNone { if rn.ExpandMode > ResourceExpandNone {
// Interpolate the count and verify it is non-negative // Interpolate the count and verify it is non-negative
rc := NewResourceConfig(rn.Config.RawCount) rc := NewResourceConfig(rn.Config.RawCount)
rc.interpolate(c) rc.interpolate(c, rn.Resource)
count, err := rn.Config.Count() count, err := rn.Config.Count()
if err == nil { if err == nil {
if count < 0 { if count < 0 {
@ -1063,7 +1063,7 @@ func (c *walkContext) validateWalkFn() depgraph.WalkFunc {
for k, p := range sharedProvider.Providers { for k, p := range sharedProvider.Providers {
// Merge the configurations to get what we use to configure with // Merge the configurations to get what we use to configure with
rc := sharedProvider.MergeConfig(false, cs[k]) rc := sharedProvider.MergeConfig(false, cs[k])
rc.interpolate(c) rc.interpolate(c, nil)
log.Printf("[INFO] Validating provider: %s", k) log.Printf("[INFO] Validating provider: %s", k)
ws, es := p.Validate(rc) ws, es := p.Validate(rc)
@ -1125,7 +1125,7 @@ func (c *walkContext) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc {
wc.Variables = make(map[string]string) wc.Variables = make(map[string]string)
rc := NewResourceConfig(m.Config.RawConfig) rc := NewResourceConfig(m.Config.RawConfig)
rc.interpolate(c) rc.interpolate(c, nil)
for k, v := range rc.Config { for k, v := range rc.Config {
wc.Variables[k] = v.(string) wc.Variables[k] = v.(string)
} }
@ -1151,7 +1151,7 @@ func (c *walkContext) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc {
for k, p := range sharedProvider.Providers { for k, p := range sharedProvider.Providers {
// Merge the configurations to get what we use to configure with // Merge the configurations to get what we use to configure with
rc := sharedProvider.MergeConfig(false, cs[k]) rc := sharedProvider.MergeConfig(false, cs[k])
rc.interpolate(c) rc.interpolate(c, nil)
log.Printf("[INFO] Configuring provider: %s", k) log.Printf("[INFO] Configuring provider: %s", k)
err := p.Configure(rc) err := p.Configure(rc)
@ -1211,7 +1211,7 @@ func (c *walkContext) genericWalkResource(
rn *GraphNodeResource, fn depgraph.WalkFunc) error { rn *GraphNodeResource, fn depgraph.WalkFunc) error {
// Interpolate the count // Interpolate the count
rc := NewResourceConfig(rn.Config.RawCount) rc := NewResourceConfig(rn.Config.RawCount)
rc.interpolate(c) rc.interpolate(c, rn.Resource)
// Expand the node to the actual resources // Expand the node to the actual resources
ns, err := rn.Expand() ns, err := rn.Expand()
@ -1260,13 +1260,13 @@ func (c *walkContext) applyProvisioners(r *Resource, is *InstanceState) error {
for _, prov := range r.Provisioners { for _, prov := range r.Provisioners {
// Interpolate since we may have variables that depend on the // Interpolate since we may have variables that depend on the
// local resource. // local resource.
if err := prov.Config.interpolate(c); err != nil { if err := prov.Config.interpolate(c, r); err != nil {
return err return err
} }
// Interpolate the conn info, since it may contain variables // Interpolate the conn info, since it may contain variables
connInfo := NewResourceConfig(prov.ConnInfo) connInfo := NewResourceConfig(prov.ConnInfo)
if err := connInfo.interpolate(c); err != nil { if err := connInfo.interpolate(c, r); err != nil {
return err return err
} }
@ -1396,7 +1396,8 @@ func (c *walkContext) persistState(r *Resource) {
// computeVars takes the State and given RawConfig and processes all // computeVars takes the State and given RawConfig and processes all
// the variables. This dynamically discovers the attributes instead of // the variables. This dynamically discovers the attributes instead of
// using a static map[string]string that the genericWalkFn uses. // using a static map[string]string that the genericWalkFn uses.
func (c *walkContext) computeVars(raw *config.RawConfig) error { func (c *walkContext) computeVars(
raw *config.RawConfig, r *Resource) error {
// If there isn't a raw configuration, don't do anything // If there isn't a raw configuration, don't do anything
if raw == nil { if raw == nil {
return nil return nil
@ -1411,6 +1412,11 @@ func (c *walkContext) computeVars(raw *config.RawConfig) error {
// Next, the actual computed variables // Next, the actual computed variables
for n, rawV := range raw.Variables { for n, rawV := range raw.Variables {
switch v := rawV.(type) { switch v := rawV.(type) {
case *config.CountVariable:
switch v.Type {
case config.CountValueIndex:
vs[n] = strconv.FormatInt(int64(r.CountIndex), 10)
}
case *config.ModuleVariable: case *config.ModuleVariable:
value, err := c.computeModuleVariable(v) value, err := c.computeModuleVariable(v)
if err != nil { if err != nil {

View File

@ -2464,6 +2464,29 @@ func TestContextPlan_countComputed(t *testing.T) {
} }
} }
func TestContextPlan_countIndex(t *testing.T) {
m := testModule(t, "plan-count-index")
p := testProvider("aws")
p.DiffFn = testDiffFn
ctx := testContext(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})
plan, err := ctx.Plan(nil)
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(plan.String())
expected := strings.TrimSpace(testTerraformPlanCountIndexStr)
if actual != expected {
t.Fatalf("bad:\n%s", actual)
}
}
func TestContextPlan_countVar(t *testing.T) { func TestContextPlan_countVar(t *testing.T) {
m := testModule(t, "plan-count-var") m := testModule(t, "plan-count-var")
p := testProvider("aws") p := testProvider("aws")

View File

@ -1704,6 +1704,7 @@ func (n *GraphNodeResource) expand(g *depgraph.Graph, count int) {
// Copy the base resource so we can fill it in // Copy the base resource so we can fill it in
resource := n.copyResource(name) resource := n.copyResource(name)
resource.CountIndex = i
resource.State = state.Primary resource.State = state.Primary
resource.Flags = flags resource.Flags = flags

View File

@ -34,6 +34,7 @@ type Resource struct {
Provider ResourceProvider Provider ResourceProvider
State *InstanceState State *InstanceState
Provisioners []*ResourceProvisionerConfig Provisioners []*ResourceProvisionerConfig
CountIndex int
Flags ResourceFlag Flags ResourceFlag
TaintedIndex int TaintedIndex int
} }
@ -92,7 +93,7 @@ type ResourceConfig struct {
// NewResourceConfig creates a new ResourceConfig from a config.RawConfig. // NewResourceConfig creates a new ResourceConfig from a config.RawConfig.
func NewResourceConfig(c *config.RawConfig) *ResourceConfig { func NewResourceConfig(c *config.RawConfig) *ResourceConfig {
result := &ResourceConfig{raw: c} result := &ResourceConfig{raw: c}
result.interpolate(nil) result.interpolate(nil, nil)
return result return result
} }
@ -190,13 +191,14 @@ func (c *ResourceConfig) get(
return current, true return current, true
} }
func (c *ResourceConfig) interpolate(ctx *walkContext) error { func (c *ResourceConfig) interpolate(
ctx *walkContext, r *Resource) error {
if c == nil { if c == nil {
return nil return nil
} }
if ctx != nil { if ctx != nil {
if err := ctx.computeVars(c.raw); err != nil { if err := ctx.computeVars(c.raw, r); err != nil {
return err return err
} }
} }

View File

@ -102,7 +102,10 @@ func TestResourceConfigGet(t *testing.T) {
rc := NewResourceConfig(rawC) rc := NewResourceConfig(rawC)
if tc.Vars != nil { if tc.Vars != nil {
ctx := NewContext(&ContextOpts{Variables: tc.Vars}) ctx := NewContext(&ContextOpts{Variables: tc.Vars})
if err := rc.interpolate(ctx.walkContext(walkInvalid, rootModulePath)); err != nil { err := rc.interpolate(
ctx.walkContext(walkInvalid, rootModulePath),
nil)
if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
} }

View File

@ -477,6 +477,21 @@ STATE:
<no state> <no state>
` `
const testTerraformPlanCountIndexStr = `
DIFF:
CREATE: aws_instance.foo.0
foo: "" => "0"
type: "" => "aws_instance"
CREATE: aws_instance.foo.1
foo: "" => "1"
type: "" => "aws_instance"
STATE:
<no state>
`
const testTerraformPlanCountOneIndexStr = ` const testTerraformPlanCountOneIndexStr = `
DIFF: DIFF:

View File

@ -0,0 +1,4 @@
resource "aws_instance" "foo" {
count = 2
foo = "${count.index}"
}