Merge pull request #355 from hashicorp/f-count-interp
Variable to interpolate count index
This commit is contained in:
commit
d28a662b6c
|
@ -199,6 +199,23 @@ func (c *Config) Validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that all count variables are valid.
|
||||||
|
for source, vs := range vars {
|
||||||
|
for _, v := range vs {
|
||||||
|
cv, ok := v.(*CountVariable)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if cv.Type == CountValueInvalid {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"%s: invalid count variable: %s",
|
||||||
|
source,
|
||||||
|
cv.FullKey()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that all references to modules are valid
|
// Check that all references to modules are valid
|
||||||
modules := make(map[string]*Module)
|
modules := make(map[string]*Module)
|
||||||
dupped := make(map[string]struct{})
|
dupped := make(map[string]struct{})
|
||||||
|
@ -258,6 +275,11 @@ func (c *Config) Validate() error {
|
||||||
// Verify count variables
|
// Verify count variables
|
||||||
for _, v := range r.RawCount.Variables {
|
for _, v := range r.RawCount.Variables {
|
||||||
switch v.(type) {
|
switch v.(type) {
|
||||||
|
case *CountVariable:
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"%s: resource count can't reference count variable: %s",
|
||||||
|
n,
|
||||||
|
v.FullKey()))
|
||||||
case *ModuleVariable:
|
case *ModuleVariable:
|
||||||
errs = append(errs, fmt.Errorf(
|
errs = append(errs, fmt.Errorf(
|
||||||
"%s: resource count can't reference module variable: %s",
|
"%s: resource count can't reference module variable: %s",
|
||||||
|
|
|
@ -60,6 +60,13 @@ func TestConfigValidate_countInt(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigValidate_countCountVar(t *testing.T) {
|
||||||
|
c := testConfig(t, "validate-count-count-var")
|
||||||
|
if err := c.Validate(); err == nil {
|
||||||
|
t.Fatal("should not be valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfigValidate_countModuleVar(t *testing.T) {
|
func TestConfigValidate_countModuleVar(t *testing.T) {
|
||||||
c := testConfig(t, "validate-count-module-var")
|
c := testConfig(t, "validate-count-module-var")
|
||||||
if err := c.Validate(); err == nil {
|
if err := c.Validate(); err == nil {
|
||||||
|
@ -88,6 +95,20 @@ func TestConfigValidate_countUserVar(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigValidate_countVar(t *testing.T) {
|
||||||
|
c := testConfig(t, "validate-count-var")
|
||||||
|
if err := c.Validate(); err != nil {
|
||||||
|
t.Fatal("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigValidate_countVarInvalid(t *testing.T) {
|
||||||
|
c := testConfig(t, "validate-count-var-invalid")
|
||||||
|
if err := c.Validate(); err == nil {
|
||||||
|
t.Fatal("should not be valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfigValidate_dupModule(t *testing.T) {
|
func TestConfigValidate_dupModule(t *testing.T) {
|
||||||
c := testConfig(t, "validate-dup-module")
|
c := testConfig(t, "validate-dup-module")
|
||||||
if err := c.Validate(); err == nil {
|
if err := c.Validate(); err == nil {
|
||||||
|
|
|
@ -52,6 +52,21 @@ type VariableInterpolation struct {
|
||||||
Variable InterpolatedVariable
|
Variable InterpolatedVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountVariable is a variable for referencing information about
|
||||||
|
// the count.
|
||||||
|
type CountVariable struct {
|
||||||
|
Type CountValueType
|
||||||
|
key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountValueType is the type of the count variable that is referenced.
|
||||||
|
type CountValueType byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
CountValueInvalid CountValueType = iota
|
||||||
|
CountValueIndex
|
||||||
|
)
|
||||||
|
|
||||||
// A ModuleVariable is a variable that is referencing the output
|
// A ModuleVariable is a variable that is referencing the output
|
||||||
// of a module, such as "${module.foo.bar}"
|
// of a module, such as "${module.foo.bar}"
|
||||||
type ModuleVariable struct {
|
type ModuleVariable struct {
|
||||||
|
@ -84,7 +99,9 @@ type UserVariable struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInterpolatedVariable(v string) (InterpolatedVariable, error) {
|
func NewInterpolatedVariable(v string) (InterpolatedVariable, error) {
|
||||||
if strings.HasPrefix(v, "var.") {
|
if strings.HasPrefix(v, "count.") {
|
||||||
|
return NewCountVariable(v)
|
||||||
|
} else if strings.HasPrefix(v, "var.") {
|
||||||
return NewUserVariable(v)
|
return NewUserVariable(v)
|
||||||
} else if strings.HasPrefix(v, "module.") {
|
} else if strings.HasPrefix(v, "module.") {
|
||||||
return NewModuleVariable(v)
|
return NewModuleVariable(v)
|
||||||
|
@ -152,6 +169,24 @@ func (i *VariableInterpolation) Variables() map[string]InterpolatedVariable {
|
||||||
return map[string]InterpolatedVariable{i.Variable.FullKey(): i.Variable}
|
return map[string]InterpolatedVariable{i.Variable.FullKey(): i.Variable}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewCountVariable(key string) (*CountVariable, error) {
|
||||||
|
var fieldType CountValueType
|
||||||
|
parts := strings.SplitN(key, ".", 2)
|
||||||
|
switch parts[1] {
|
||||||
|
case "index":
|
||||||
|
fieldType = CountValueIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CountVariable{
|
||||||
|
Type: fieldType,
|
||||||
|
key: key,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CountVariable) FullKey() string {
|
||||||
|
return c.key
|
||||||
|
}
|
||||||
|
|
||||||
func NewModuleVariable(key string) (*ModuleVariable, error) {
|
func NewModuleVariable(key string) (*ModuleVariable, error) {
|
||||||
parts := strings.SplitN(key, ".", 3)
|
parts := strings.SplitN(key, ".", 3)
|
||||||
if len(parts) < 3 {
|
if len(parts) < 3 {
|
||||||
|
|
|
@ -29,6 +29,22 @@ func TestNewInterpolatedVariable(t *testing.T) {
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"count.index",
|
||||||
|
&CountVariable{
|
||||||
|
Type: CountValueIndex,
|
||||||
|
key: "count.index",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count.nope",
|
||||||
|
&CountVariable{
|
||||||
|
Type: CountValueInvalid,
|
||||||
|
key: "count.nope",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
resource "aws_instance" "web" {
|
||||||
|
count = "${count.index}"
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
foo = "${count.foo}"
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
foo = "${count.index}"
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -2464,6 +2464,52 @@ 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_countIndexZero(t *testing.T) {
|
||||||
|
m := testModule(t, "plan-count-index-zero")
|
||||||
|
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(testTerraformPlanCountIndexZeroStr)
|
||||||
|
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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -477,6 +477,33 @@ 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 testTerraformPlanCountIndexZeroStr = `
|
||||||
|
DIFF:
|
||||||
|
|
||||||
|
CREATE: aws_instance.foo
|
||||||
|
foo: "" => "0"
|
||||||
|
type: "" => "aws_instance"
|
||||||
|
|
||||||
|
STATE:
|
||||||
|
|
||||||
|
<no state>
|
||||||
|
`
|
||||||
|
|
||||||
const testTerraformPlanCountOneIndexStr = `
|
const testTerraformPlanCountOneIndexStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
foo = "${count.index}"
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
count = 2
|
||||||
|
foo = "${count.index}"
|
||||||
|
}
|
|
@ -14,7 +14,9 @@ into strings. These interpolations are wrapped in `${}`, such as
|
||||||
The interpolation syntax is powerful and allows you to reference
|
The interpolation syntax is powerful and allows you to reference
|
||||||
variables, attributes of resources, call functions, etc.
|
variables, attributes of resources, call functions, etc.
|
||||||
|
|
||||||
To reference variables, use the `var.` prefix followed by the
|
## Available Variables
|
||||||
|
|
||||||
|
**To reference user variables**, use the `var.` prefix followed by the
|
||||||
variable name. For example, `${var.foo}` will interpolate the
|
variable name. For example, `${var.foo}` will interpolate the
|
||||||
`foo` variable value. If the variable is a mapping, then you
|
`foo` variable value. If the variable is a mapping, then you
|
||||||
can reference static keys in the map with the syntax
|
can reference static keys in the map with the syntax
|
||||||
|
@ -22,18 +24,28 @@ can reference static keys in the map with the syntax
|
||||||
get the value of the `us-east-1` key within the `amis` variable
|
get the value of the `us-east-1` key within the `amis` variable
|
||||||
that is a mapping.
|
that is a mapping.
|
||||||
|
|
||||||
To reference attributes of other resources, the syntax is
|
**To reference attributes of other resources**, the syntax is
|
||||||
`TYPE.NAME.ATTRIBUTE`. For example, `${aws_instance.web.id}`
|
`TYPE.NAME.ATTRIBUTE`. For example, `${aws_instance.web.id}`
|
||||||
will interpolate the ID attribute from the "aws\_instance"
|
will interpolate the ID attribute from the "aws\_instance"
|
||||||
resource named "web".
|
resource named "web".
|
||||||
|
|
||||||
Finally, Terraform ships with built-in functions. Functions
|
**To reference outputs from a module**, the syntax is
|
||||||
are called with the syntax `name(arg, arg2, ...)`. For example,
|
`MODULE.NAME.OUTPUT`. For example `${module.foo.bar}` will
|
||||||
to read a file: `${file("path.txt")}`. The built-in functions
|
interpolate the "bar" output from the "foo"
|
||||||
are documented below.
|
[module](/docs/modules/index.html).
|
||||||
|
|
||||||
|
**To reference count information**, the syntax is `count.FIELD`.
|
||||||
|
For example, `${count.index}` will interpolate the current index
|
||||||
|
in a multi-count resource. For more information on count, see the
|
||||||
|
resource configuration page.
|
||||||
|
|
||||||
## Built-in Functions
|
## Built-in Functions
|
||||||
|
|
||||||
|
Terraform ships with built-in functions. Functions are called with
|
||||||
|
the syntax `name(arg, arg2, ...)`. For example,
|
||||||
|
to read a file: `${file("path.txt")}`. The built-in functions
|
||||||
|
are documented below.
|
||||||
|
|
||||||
The supported built-in functions are:
|
The supported built-in functions are:
|
||||||
|
|
||||||
* `concat(args...)` - Concatenates the values of multiple arguments into
|
* `concat(args...)` - Concatenates the values of multiple arguments into
|
||||||
|
|
|
@ -42,7 +42,9 @@ resource type in the
|
||||||
There are **meta-parameters** available to all resources:
|
There are **meta-parameters** available to all resources:
|
||||||
|
|
||||||
* `count` (int) - The number of identical resources to create.
|
* `count` (int) - The number of identical resources to create.
|
||||||
This doesn't apply to all resources.
|
This doesn't apply to all resources. You can use the `${count.index}`
|
||||||
|
[interpolation](/docs/configuration/interpolation.html) to reference
|
||||||
|
the current count index in your resource.
|
||||||
|
|
||||||
* `depends_on` (list of strings) - Explicit dependencies that this
|
* `depends_on` (list of strings) - Explicit dependencies that this
|
||||||
resource has. These dependencies will be created before this
|
resource has. These dependencies will be created before this
|
||||||
|
|
Loading…
Reference in New Issue