2015-02-04 17:44:23 -06:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
2015-02-04 19:02:18 -06:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2015-02-04 17:44:23 -06:00
|
|
|
"testing"
|
2015-08-10 15:03:02 -05:00
|
|
|
"time"
|
2016-08-09 15:14:40 -05:00
|
|
|
|
2018-05-22 18:02:22 -05:00
|
|
|
"github.com/hashicorp/hil"
|
2018-05-30 10:25:28 -05:00
|
|
|
"github.com/hashicorp/terraform/config"
|
2018-07-05 12:33:29 -05:00
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
2018-05-04 21:24:06 -05:00
|
|
|
"github.com/hashicorp/terraform/configs"
|
2018-05-17 19:52:01 -05:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
2018-05-04 21:24:06 -05:00
|
|
|
|
2016-11-12 18:50:26 -06:00
|
|
|
"github.com/hashicorp/go-version"
|
2016-08-09 15:14:40 -05:00
|
|
|
"github.com/hashicorp/terraform/flatmap"
|
2017-10-19 20:48:08 -05:00
|
|
|
tfversion "github.com/hashicorp/terraform/version"
|
2015-02-04 17:44:23 -06:00
|
|
|
)
|
|
|
|
|
2016-11-12 18:50:26 -06:00
|
|
|
func TestNewContextRequiredVersion(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
Name string
|
|
|
|
Module string
|
|
|
|
Version string
|
|
|
|
Value string
|
|
|
|
Err bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"no requirement",
|
|
|
|
"",
|
|
|
|
"0.1.0",
|
|
|
|
"",
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"doesn't match",
|
|
|
|
"",
|
|
|
|
"0.1.0",
|
|
|
|
"> 0.6.0",
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"matches",
|
|
|
|
"",
|
|
|
|
"0.7.0",
|
|
|
|
"> 0.6.0",
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"module matches",
|
|
|
|
"context-required-version-module",
|
|
|
|
"0.5.0",
|
|
|
|
"",
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
"module doesn't match",
|
|
|
|
"context-required-version-module",
|
|
|
|
"0.4.0",
|
|
|
|
"",
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range cases {
|
|
|
|
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
|
|
|
|
// Reset the version for the tests
|
2017-10-19 20:48:08 -05:00
|
|
|
old := tfversion.SemVer
|
|
|
|
tfversion.SemVer = version.Must(version.NewVersion(tc.Version))
|
|
|
|
defer func() { tfversion.SemVer = old }()
|
2016-11-12 18:50:26 -06:00
|
|
|
|
|
|
|
name := "context-required-version"
|
|
|
|
if tc.Module != "" {
|
|
|
|
name = tc.Module
|
|
|
|
}
|
|
|
|
mod := testModule(t, name)
|
|
|
|
if tc.Value != "" {
|
2018-05-04 21:24:06 -05:00
|
|
|
constraint, err := version.NewConstraint(tc.Value)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("can't parse %q as version constraint", tc.Value)
|
|
|
|
}
|
|
|
|
mod.Module.CoreVersionConstraints = append(mod.Module.CoreVersionConstraints, configs.VersionConstraint{
|
|
|
|
Required: constraint,
|
|
|
|
})
|
2016-11-12 18:50:26 -06:00
|
|
|
}
|
2018-05-04 21:24:06 -05:00
|
|
|
_, diags := NewContext(&ContextOpts{
|
|
|
|
Config: mod,
|
2016-11-12 18:50:26 -06:00
|
|
|
})
|
2018-05-04 21:24:06 -05:00
|
|
|
if diags.HasErrors() != tc.Err {
|
|
|
|
t.Fatalf("err: %s", diags.Err())
|
2016-11-12 18:50:26 -06:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-11 13:07:54 -06:00
|
|
|
func TestNewContextState(t *testing.T) {
|
|
|
|
cases := map[string]struct {
|
|
|
|
Input *ContextOpts
|
|
|
|
Err bool
|
|
|
|
}{
|
|
|
|
"empty TFVersion": {
|
|
|
|
&ContextOpts{
|
|
|
|
State: &State{},
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
|
|
|
"past TFVersion": {
|
|
|
|
&ContextOpts{
|
|
|
|
State: &State{TFVersion: "0.1.2"},
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
|
|
|
"equal TFVersion": {
|
|
|
|
&ContextOpts{
|
2017-10-19 20:48:08 -05:00
|
|
|
State: &State{TFVersion: tfversion.Version},
|
2016-03-11 13:07:54 -06:00
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
|
|
|
"future TFVersion": {
|
|
|
|
&ContextOpts{
|
|
|
|
State: &State{TFVersion: "99.99.99"},
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"future TFVersion, allowed": {
|
|
|
|
&ContextOpts{
|
|
|
|
State: &State{TFVersion: "99.99.99"},
|
|
|
|
StateFutureAllowed: true,
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, tc := range cases {
|
|
|
|
ctx, err := NewContext(tc.Input)
|
|
|
|
if (err != nil) != tc.Err {
|
|
|
|
t.Fatalf("%s: err: %s", k, err)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Version should always be set to our current
|
2017-10-19 20:48:08 -05:00
|
|
|
if ctx.state.TFVersion != tfversion.Version {
|
2016-03-11 13:07:54 -06:00
|
|
|
t.Fatalf("%s: state not set to current version", k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:15:36 -06:00
|
|
|
func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
2017-11-07 12:09:36 -06:00
|
|
|
t.Helper()
|
2016-10-21 16:25:05 -05:00
|
|
|
// Enable the shadow graph
|
|
|
|
opts.Shadow = true
|
|
|
|
|
2018-05-17 19:52:01 -05:00
|
|
|
ctx, diags := NewContext(opts)
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("failed to create test context\n\n%s\n", diags.Err())
|
2016-03-11 13:07:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return ctx
|
2015-02-04 17:44:23 -06:00
|
|
|
}
|
2015-02-13 20:09:45 -06:00
|
|
|
|
2016-10-23 20:53:00 -05:00
|
|
|
func testDataApplyFn(
|
|
|
|
info *InstanceInfo,
|
|
|
|
d *InstanceDiff) (*InstanceState, error) {
|
|
|
|
return testApplyFn(info, new(InstanceState), d)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testDataDiffFn(
|
|
|
|
info *InstanceInfo,
|
|
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
|
|
|
return testDiffFn(info, new(InstanceState), c)
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
func testApplyFn(
|
|
|
|
info *InstanceInfo,
|
|
|
|
s *InstanceState,
|
|
|
|
d *InstanceDiff) (*InstanceState, error) {
|
|
|
|
if d.Destroy {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2018-05-30 10:25:28 -05:00
|
|
|
// find the OLD id, which is probably in the ID field for now, but eventually
|
|
|
|
// ID should only be in one place.
|
|
|
|
id := s.ID
|
|
|
|
if id == "" {
|
|
|
|
id = s.Attributes["id"]
|
|
|
|
}
|
2015-02-13 20:09:45 -06:00
|
|
|
if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed {
|
|
|
|
id = idAttr.New
|
|
|
|
}
|
|
|
|
|
2018-05-30 10:25:28 -05:00
|
|
|
if id == "" || id == config.UnknownVariableValue {
|
|
|
|
id = "foo"
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
result := &InstanceState{
|
2015-02-26 11:50:18 -06:00
|
|
|
ID: id,
|
|
|
|
Attributes: make(map[string]string),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy all the prior attributes
|
|
|
|
for k, v := range s.Attributes {
|
|
|
|
result.Attributes[k] = v
|
2015-02-13 20:09:45 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if d != nil {
|
|
|
|
result = result.MergeDiff(d)
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func testDiffFn(
|
|
|
|
info *InstanceInfo,
|
|
|
|
s *InstanceState,
|
|
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
2016-04-21 14:59:10 -05:00
|
|
|
diff := new(InstanceDiff)
|
2015-02-13 20:09:45 -06:00
|
|
|
diff.Attributes = make(map[string]*ResourceAttrDiff)
|
|
|
|
|
2016-04-21 14:59:10 -05:00
|
|
|
if s != nil {
|
|
|
|
diff.DestroyTainted = s.Tainted
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
for k, v := range c.Raw {
|
2016-02-24 09:55:55 -06:00
|
|
|
// Ignore __-prefixed keys since they're used for magic
|
|
|
|
if k[0] == '_' && k[1] == '_' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
if k == "nil" {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This key is used for other purposes
|
|
|
|
if k == "compute_value" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if k == "compute" {
|
2018-05-24 15:11:03 -05:00
|
|
|
if v == hil.UnknownValue || v == "unknown" {
|
2018-05-22 18:02:22 -05:00
|
|
|
// compute wasn't set in the config, so don't use these
|
|
|
|
// computed values from the schema.
|
|
|
|
delete(c.Raw, k)
|
|
|
|
delete(c.Raw, "compute_value")
|
|
|
|
|
|
|
|
// we need to remove this from the list of ComputedKeys too,
|
|
|
|
// since it would get re-added to the diff further down
|
|
|
|
newComputed := make([]string, 0, len(c.ComputedKeys))
|
|
|
|
for _, ck := range c.ComputedKeys {
|
|
|
|
if ck == "compute" || ck == "compute_value" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
newComputed = append(newComputed, ck)
|
|
|
|
}
|
|
|
|
c.ComputedKeys = newComputed
|
|
|
|
|
2018-05-24 15:11:03 -05:00
|
|
|
if v == "unknown" {
|
|
|
|
diff.Attributes["unknown"] = &ResourceAttrDiff{
|
|
|
|
Old: "",
|
|
|
|
New: "",
|
|
|
|
NewComputed: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
c.ComputedKeys = append(c.ComputedKeys, "unknown")
|
|
|
|
}
|
|
|
|
|
2018-05-22 18:02:22 -05:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
attrDiff := &ResourceAttrDiff{
|
|
|
|
Old: "",
|
|
|
|
New: "",
|
|
|
|
NewComputed: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
if cv, ok := c.Config["compute_value"]; ok {
|
|
|
|
if cv.(string) == "1" {
|
|
|
|
attrDiff.NewComputed = false
|
|
|
|
attrDiff.New = fmt.Sprintf("computed_%s", v.(string))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
diff.Attributes[v.(string)] = attrDiff
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this key is not computed, then look it up in the
|
|
|
|
// cleaned config.
|
|
|
|
found := false
|
|
|
|
for _, ck := range c.ComputedKeys {
|
|
|
|
if ck == k {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
v = c.Config[k]
|
|
|
|
}
|
|
|
|
|
2016-08-10 10:37:55 -05:00
|
|
|
for k, attrDiff := range testFlatAttrDiffs(k, v) {
|
2018-05-21 18:14:40 -05:00
|
|
|
// we need to ignore 'id' for now, since it's always inferred to be
|
|
|
|
// computed.
|
|
|
|
if k == "id" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-08-10 10:37:55 -05:00
|
|
|
if k == "require_new" {
|
|
|
|
attrDiff.RequiresNew = true
|
2016-08-09 15:14:40 -05:00
|
|
|
}
|
2016-08-10 10:37:55 -05:00
|
|
|
if _, ok := c.Raw["__"+k+"_requires_new"]; ok {
|
|
|
|
attrDiff.RequiresNew = true
|
|
|
|
}
|
2017-03-20 16:17:14 -05:00
|
|
|
|
|
|
|
if attr, ok := s.Attributes[k]; ok {
|
|
|
|
attrDiff.Old = attr
|
|
|
|
}
|
|
|
|
|
2016-08-10 10:37:55 -05:00
|
|
|
diff.Attributes[k] = attrDiff
|
2015-02-13 20:09:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, k := range c.ComputedKeys {
|
2018-05-21 18:14:40 -05:00
|
|
|
if k == "id" {
|
|
|
|
continue
|
|
|
|
}
|
2015-02-13 20:09:45 -06:00
|
|
|
diff.Attributes[k] = &ResourceAttrDiff{
|
|
|
|
Old: "",
|
|
|
|
NewComputed: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 14:59:10 -05:00
|
|
|
// If we recreate this resource because it's tainted, we keep all attrs
|
|
|
|
if !diff.RequiresNew() {
|
|
|
|
for k, v := range diff.Attributes {
|
|
|
|
if v.NewComputed {
|
|
|
|
continue
|
|
|
|
}
|
2015-02-13 20:09:45 -06:00
|
|
|
|
2016-04-21 14:59:10 -05:00
|
|
|
old, ok := s.Attributes[k]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if old == v.New {
|
|
|
|
delete(diff.Attributes, k)
|
|
|
|
}
|
2015-02-13 20:09:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !diff.Empty() {
|
|
|
|
diff.Attributes["type"] = &ResourceAttrDiff{
|
|
|
|
Old: "",
|
|
|
|
New: info.Type,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 14:59:10 -05:00
|
|
|
return diff, nil
|
2015-02-13 20:09:45 -06:00
|
|
|
}
|
|
|
|
|
2016-08-09 15:14:40 -05:00
|
|
|
// generate ResourceAttrDiffs for nested data structures in tests
|
|
|
|
func testFlatAttrDiffs(k string, i interface{}) map[string]*ResourceAttrDiff {
|
|
|
|
diffs := make(map[string]*ResourceAttrDiff)
|
2016-08-10 10:37:55 -05:00
|
|
|
// check for strings and empty containers first
|
|
|
|
switch t := i.(type) {
|
|
|
|
case string:
|
|
|
|
diffs[k] = &ResourceAttrDiff{New: t}
|
|
|
|
return diffs
|
|
|
|
case map[string]interface{}:
|
|
|
|
if len(t) == 0 {
|
|
|
|
diffs[k] = &ResourceAttrDiff{New: ""}
|
|
|
|
return diffs
|
|
|
|
}
|
|
|
|
case []interface{}:
|
|
|
|
if len(t) == 0 {
|
|
|
|
diffs[k] = &ResourceAttrDiff{New: ""}
|
|
|
|
return diffs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
flat := flatmap.Flatten(map[string]interface{}{k: i})
|
2016-08-09 15:14:40 -05:00
|
|
|
|
|
|
|
for k, v := range flat {
|
|
|
|
attrDiff := &ResourceAttrDiff{
|
|
|
|
Old: "",
|
|
|
|
New: v,
|
|
|
|
}
|
|
|
|
diffs[k] = attrDiff
|
|
|
|
}
|
|
|
|
|
|
|
|
return diffs
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
func testProvider(prefix string) *MockResourceProvider {
|
|
|
|
p := new(MockResourceProvider)
|
|
|
|
p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
p.ResourcesReturn = []ResourceType{
|
|
|
|
ResourceType{
|
|
|
|
Name: fmt.Sprintf("%s_instance", prefix),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-05-17 19:52:01 -05:00
|
|
|
p.GetSchemaReturn = testProviderSchema(prefix)
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func testProvisioner() *MockResourceProvisioner {
|
|
|
|
p := new(MockResourceProvisioner)
|
2018-05-17 19:52:01 -05:00
|
|
|
p.GetConfigSchemaReturnSchema = &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"command": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-29 16:35:58 -05:00
|
|
|
"order": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-23 12:39:36 -05:00
|
|
|
"when": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-17 19:52:01 -05:00
|
|
|
},
|
|
|
|
}
|
2015-02-13 20:09:45 -06:00
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2015-03-04 12:15:53 -06:00
|
|
|
func checkStateString(t *testing.T, state *State, expected string) {
|
2017-11-07 12:49:10 -06:00
|
|
|
t.Helper()
|
2015-03-04 12:15:53 -06:00
|
|
|
actual := strings.TrimSpace(state.String())
|
|
|
|
expected = strings.TrimSpace(expected)
|
|
|
|
|
|
|
|
if actual != expected {
|
|
|
|
t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-30 15:17:28 -05:00
|
|
|
func resourceState(resourceType, resourceID string) *ResourceState {
|
2018-05-17 19:52:01 -05:00
|
|
|
providerResource := strings.Split(resourceType, "_")
|
2015-03-30 15:17:28 -05:00
|
|
|
return &ResourceState{
|
|
|
|
Type: resourceType,
|
|
|
|
Primary: &InstanceState{
|
|
|
|
ID: resourceID,
|
2018-01-29 17:00:18 -06:00
|
|
|
Attributes: map[string]string{
|
|
|
|
"id": resourceID,
|
|
|
|
},
|
2015-03-30 15:17:28 -05:00
|
|
|
},
|
2018-05-17 19:52:01 -05:00
|
|
|
Provider: "provider." + providerResource[0],
|
2015-03-30 15:17:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-10 15:03:02 -05:00
|
|
|
// Test helper that gives a function 3 seconds to finish, assumes deadlock and
|
|
|
|
// fails test if it does not.
|
|
|
|
func testCheckDeadlock(t *testing.T, f func()) {
|
2017-11-07 12:49:10 -06:00
|
|
|
t.Helper()
|
2015-08-10 15:03:02 -05:00
|
|
|
timeout := make(chan bool, 1)
|
|
|
|
done := make(chan bool, 1)
|
|
|
|
go func() {
|
|
|
|
time.Sleep(3 * time.Second)
|
|
|
|
timeout <- true
|
|
|
|
}()
|
|
|
|
go func(f func(), done chan bool) {
|
|
|
|
defer func() { done <- true }()
|
|
|
|
f()
|
|
|
|
}(f, done)
|
|
|
|
select {
|
|
|
|
case <-timeout:
|
|
|
|
t.Fatalf("timed out! probably deadlock")
|
|
|
|
case <-done:
|
|
|
|
// ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-17 19:52:01 -05:00
|
|
|
func testProviderSchema(name string) *ProviderSchema {
|
|
|
|
return &ProviderSchema{
|
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"region": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-23 12:39:36 -05:00
|
|
|
"value": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"root": {
|
|
|
|
Type: cty.Number,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-17 19:52:01 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
name + "_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"ami": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"dep": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"num": {
|
|
|
|
Type: cty.Number,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"require_new": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"var": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"compute": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"compute_value": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"value": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"output": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"write": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"instance": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"vpc_id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_eip": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"instance": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_resource": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"value": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"random": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_ami_list": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"ids": {
|
|
|
|
Type: cty.List(cty.String),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_remote_state": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"output": {
|
2018-05-23 12:39:36 -05:00
|
|
|
Type: cty.Map(cty.String),
|
|
|
|
Computed: true,
|
2018-05-17 19:52:01 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_file": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-06-01 13:06:25 -05:00
|
|
|
"rendered": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
2018-05-22 18:02:22 -05:00
|
|
|
"__template_requires_new": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-17 19:52:01 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
|
|
|
name + "_data_source": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_remote_state": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-23 12:39:36 -05:00
|
|
|
"output": {
|
|
|
|
Type: cty.Map(cty.String),
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-05-17 19:52:01 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
name + "_file": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2018-06-01 13:06:25 -05:00
|
|
|
"rendered": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
2018-05-17 19:52:01 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
const testContextGraph = `
|
|
|
|
root: root
|
|
|
|
aws_instance.bar
|
|
|
|
aws_instance.bar -> provider.aws
|
|
|
|
aws_instance.foo
|
|
|
|
aws_instance.foo -> provider.aws
|
|
|
|
provider.aws
|
|
|
|
root
|
|
|
|
root -> aws_instance.bar
|
|
|
|
root -> aws_instance.foo
|
|
|
|
`
|
|
|
|
|
|
|
|
const testContextRefreshModuleStr = `
|
2016-04-21 14:59:10 -05:00
|
|
|
aws_instance.web: (tainted)
|
|
|
|
ID = bar
|
2017-11-07 19:53:18 -06:00
|
|
|
provider = provider.aws
|
2015-02-13 20:09:45 -06:00
|
|
|
|
|
|
|
module.child:
|
|
|
|
aws_instance.web:
|
|
|
|
ID = new
|
2017-11-07 19:53:18 -06:00
|
|
|
provider = provider.aws
|
2015-02-13 20:09:45 -06:00
|
|
|
`
|
|
|
|
|
2015-04-10 15:51:22 -05:00
|
|
|
const testContextRefreshOutputStr = `
|
|
|
|
aws_instance.web:
|
|
|
|
ID = foo
|
2017-11-07 19:53:18 -06:00
|
|
|
provider = provider.aws
|
2015-04-10 15:51:22 -05:00
|
|
|
foo = bar
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
foo = bar
|
|
|
|
`
|
|
|
|
|
2015-02-13 20:09:45 -06:00
|
|
|
const testContextRefreshOutputPartialStr = `
|
|
|
|
<no state>
|
|
|
|
`
|
|
|
|
|
|
|
|
const testContextRefreshTaintedStr = `
|
2016-04-21 14:59:10 -05:00
|
|
|
aws_instance.web: (tainted)
|
|
|
|
ID = foo
|
2017-11-07 19:53:18 -06:00
|
|
|
provider = provider.aws
|
2015-02-13 20:09:45 -06:00
|
|
|
`
|