From 70b7243dd6606286ec77f7b4448ca5d4f572e0c5 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 30 Jun 2015 12:54:32 +0100 Subject: [PATCH 01/48] helper: Add resource.PrefixedUniqueId --- helper/resource/id.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/helper/resource/id.go b/helper/resource/id.go index b3af422fc..ea0ae1916 100644 --- a/helper/resource/id.go +++ b/helper/resource/id.go @@ -9,13 +9,18 @@ import ( const UniqueIdPrefix = `terraform-` -// Helper for a resource to generate a unique identifier +// Helper for a resource to generate a unique identifier w/ default prefix +func UniqueId() string { + return PrefixedUniqueId(UniqueIdPrefix) +} + +// Helper for a resource to generate a unique identifier w/ given prefix // // This uses a simple RFC 4122 v4 UUID with some basic cosmetic filters // applied (base32, remove padding, downcase) to make visually distinguishing // identifiers easier. -func UniqueId() string { - return fmt.Sprintf("%s%s", UniqueIdPrefix, +func PrefixedUniqueId(prefix string) string { + return fmt.Sprintf("%s%s", prefix, strings.ToLower( strings.Replace( base32.StdEncoding.EncodeToString(uuidV4()), From 676d490d403f4234b5a2baa579328da28c49d476 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 30 Jun 2015 13:01:07 +0100 Subject: [PATCH 02/48] provider/aws: Allow elb name to be generated --- builtin/providers/aws/resource_aws_elb.go | 16 +++++++++++++--- .../docs/providers/aws/r/elb.html.markdown | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index b76cc7131..8a5c9b413 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -11,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/elb" "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -24,7 +25,8 @@ func resourceAwsElb() *schema.Resource { Schema: map[string]*schema.Schema{ "name": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, + Computed: true, ForceNew: true, ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { value := v.(string) @@ -211,10 +213,18 @@ func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { return err } + var elbName string + if v, ok := d.GetOk("name"); ok { + elbName = v.(string) + } else { + elbName = resource.PrefixedUniqueId("tf-lb-") + d.Set("name", elbName) + } + tags := tagsFromMapELB(d.Get("tags").(map[string]interface{})) // Provision the elb elbOpts := &elb.CreateLoadBalancerInput{ - LoadBalancerName: aws.String(d.Get("name").(string)), + LoadBalancerName: aws.String(elbName), Listeners: listeners, Tags: tags, } @@ -241,7 +251,7 @@ func resourceAwsElbCreate(d *schema.ResourceData, meta interface{}) error { } // Assign the elb's unique identifier for use later - d.SetId(d.Get("name").(string)) + d.SetId(elbName) log.Printf("[INFO] ELB ID: %s", d.Id()) // Enable partial mode and record what we set diff --git a/website/source/docs/providers/aws/r/elb.html.markdown b/website/source/docs/providers/aws/r/elb.html.markdown index 9c63788d3..824a5507f 100644 --- a/website/source/docs/providers/aws/r/elb.html.markdown +++ b/website/source/docs/providers/aws/r/elb.html.markdown @@ -57,7 +57,7 @@ resource "aws_elb" "bar" { The following arguments are supported: -* `name` - (Required) The name of the ELB +* `name` - (Optional) The name of the ELB. By default generated by terraform. * `availability_zones` - (Required for an EC2-classic ELB) The AZ's to serve traffic in. * `security_groups` - (Optional) A list of security group IDs to assign to the ELB. * `subnets` - (Required for a VPC ELB) A list of subnet IDs to attach to the ELB. From 7756bf3aefd58f2a8ebaa69e9bccde5848ce5c45 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 14 Jul 2015 13:29:03 -0500 Subject: [PATCH 03/48] provider/aws: Fix issue with detecting differences in DB Parameters Fixes #2718 --- builtin/providers/aws/resource_aws_db_parameter_group.go | 2 +- builtin/providers/aws/structure.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/builtin/providers/aws/resource_aws_db_parameter_group.go b/builtin/providers/aws/resource_aws_db_parameter_group.go index 9489394dc..b274605a7 100644 --- a/builtin/providers/aws/resource_aws_db_parameter_group.go +++ b/builtin/providers/aws/resource_aws_db_parameter_group.go @@ -166,7 +166,7 @@ func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{}) Parameters: parameters, } - log.Printf("[DEBUG] Modify DB Parameter Group: %#v", modifyOpts) + log.Printf("[DEBUG] Modify DB Parameter Group: %s", modifyOpts) _, err = rdsconn.ModifyDBParameterGroup(&modifyOpts) if err != nil { return fmt.Errorf("Error modifying DB Parameter Group: %s", err) diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 59bc61b14..b22a0f1c8 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -186,13 +186,17 @@ func expandIPPerms( // Takes the result of flatmap.Expand for an array of parameters and // returns Parameter API compatible objects func expandParameters(configured []interface{}) ([]*rds.Parameter, error) { - parameters := make([]*rds.Parameter, 0, len(configured)) + var parameters []*rds.Parameter // Loop over our configured parameters and create // an array of aws-sdk-go compatabile objects for _, pRaw := range configured { data := pRaw.(map[string]interface{}) + if data["name"].(string) == "" { + continue + } + p := &rds.Parameter{ ApplyMethod: aws.String(data["apply_method"].(string)), ParameterName: aws.String(data["name"].(string)), From 975e1a6c2c7af386060da504b82d14e19b1deeab Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 14 Jul 2015 16:39:50 -0500 Subject: [PATCH 04/48] provider/aws: Check credentials before attempting to do anything --- builtin/providers/aws/config.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index bc465394c..a1a0dd361 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform/helper/multierror" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/aws/aws-sdk-go/service/cloudwatch" @@ -85,6 +86,14 @@ func (c *Config) Client() (interface{}, error) { MaxRetries: c.MaxRetries, } + log.Println("[INFO] Initializing IAM Connection") + client.iamconn = iam.New(awsConfig) + + err := c.ValidateCredentials(client.iamconn) + if err != nil { + errs = append(errs, err) + } + log.Println("[INFO] Initializing DynamoDB connection") client.dynamodbconn = dynamodb.New(awsConfig) @@ -103,15 +112,12 @@ func (c *Config) Client() (interface{}, error) { log.Println("[INFO] Initializing RDS Connection") client.rdsconn = rds.New(awsConfig) - log.Println("[INFO] Initializing IAM Connection") - client.iamconn = iam.New(awsConfig) - log.Println("[INFO] Initializing Kinesis Connection") client.kinesisconn = kinesis.New(awsConfig) - err := c.ValidateAccountId(client.iamconn) - if err != nil { - errs = append(errs, err) + authErr := c.ValidateAccountId(client.iamconn) + if authErr != nil { + errs = append(errs, authErr) } log.Println("[INFO] Initializing AutoScaling connection") @@ -165,6 +171,21 @@ func (c *Config) ValidateRegion() error { return fmt.Errorf("Not a valid region: %s", c.Region) } +// Validate credentials early and fail before we do any graph walking +func (c *Config) ValidateCredentials(iamconn *iam.IAM) error { + _, err := iamconn.GetUser(nil) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "SignatureDoesNotMatch" { + return fmt.Errorf("Failed authenticating with AWS: please verify credentials") + } + } + return err + } + + return nil +} + // ValidateAccountId returns a context-specific error if the configured account // id is explicitly forbidden or not authorised; and nil if it is authorised. func (c *Config) ValidateAccountId(iamconn *iam.IAM) error { From 96a04c16f6a182804af7f709dc367538464e88b5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 19 Jul 2015 13:41:57 -0700 Subject: [PATCH 05/48] terraform: state ModuleOrphans should return grandchild orphans --- terraform/state.go | 33 ++++++++++++++++++++++++++++++--- terraform/state_test.go | 22 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index d3b19c9de..520988668 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -111,17 +111,44 @@ func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { } } - // Go over the direct children and find any that aren't in our - // keys. + // Go over the direct children and find any that aren't in our keys. var orphans [][]string + direct := make(map[string]struct{}, len(childrenKeys)) for _, m := range s.Children(path) { - if _, ok := childrenKeys[m.Path[len(m.Path)-1]]; ok { + key := m.Path[len(m.Path)-1] + if _, ok := childrenKeys[key]; ok { continue } + // Record that we found this key as a direct child. We use this + // later to find orphan nested modules. + direct[key] = struct{}{} + orphans = append(orphans, m.Path) } + // Find the orphans that are nested... + for _, m := range s.Modules { + // We only want modules that are at least grandchildren + if len(m.Path) < len(path)+2 { + continue + } + + // If it isn't part of our tree, continue + if !reflect.DeepEqual(path, m.Path[:len(path)]) { + continue + } + + // If we have the direct child, then just skip it. + key := m.Path[len(m.Path)-1] + if _, ok := direct[key]; ok { + continue + } + + // Add this orphan + orphans = append(orphans, m.Path[:len(path)+1]) + } + return orphans } diff --git a/terraform/state_test.go b/terraform/state_test.go index 7f3dbb567..eeb974d0b 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -85,6 +85,28 @@ func TestStateModuleOrphans(t *testing.T) { } } +func TestStateModuleOrphans_nested(t *testing.T) { + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: RootModulePath, + }, + &ModuleState{ + Path: []string{RootModuleName, "foo", "bar"}, + }, + }, + } + + actual := state.ModuleOrphans(RootModulePath, nil) + expected := [][]string{ + []string{RootModuleName, "foo"}, + } + + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: %#v", actual) + } +} + func TestStateModuleOrphans_nilConfig(t *testing.T) { state := &State{ Modules: []*ModuleState{ From 61d275f47575fbd429dcc94fe478c8027ea954fa Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 19 Jul 2015 13:53:31 -0700 Subject: [PATCH 06/48] terraform: get nested oprhans in the transform --- terraform/context_apply_test.go | 48 +++++++++++++++++++ terraform/terraform_test.go | 5 ++ .../apply-destroy-nested-module/child/main.tf | 3 ++ .../child/subchild/main.tf | 1 + .../apply-destroy-nested-module/main.tf | 5 ++ terraform/transform_orphan.go | 13 ++++- 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 terraform/test-fixtures/apply-destroy-nested-module/child/main.tf create mode 100644 terraform/test-fixtures/apply-destroy-nested-module/child/subchild/main.tf create mode 100644 terraform/test-fixtures/apply-destroy-nested-module/main.tf diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 2f4d43296..96dd8ad5c 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -2097,6 +2097,54 @@ func TestContext2Apply_destroy(t *testing.T) { } } +func TestContext2Apply_destroyNestedModule(t *testing.T) { + m := testModule(t, "apply-destroy-nested-module") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + s := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: []string{"root", "child", "subchild"}, + Resources: map[string]*ResourceState{ + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + } + + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + State: s, + }) + + // First plan and apply a create operation + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + state, err := ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + + // Test that things were destroyed + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestContext2Apply_destroyOutputs(t *testing.T) { m := testModule(t, "apply-destroy-outputs") h := new(HookRecordApplyOrder) diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 59dad38d4..c84e9803c 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -483,6 +483,11 @@ const testTerraformApplyDestroyStr = ` ` +const testTerraformApplyDestroyNestedModuleStr = ` +module.child.subchild: + +` + const testTerraformApplyErrorStr = ` aws_instance.bar: ID = bar diff --git a/terraform/test-fixtures/apply-destroy-nested-module/child/main.tf b/terraform/test-fixtures/apply-destroy-nested-module/child/main.tf new file mode 100644 index 000000000..852bce8b9 --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-nested-module/child/main.tf @@ -0,0 +1,3 @@ +module "subchild" { + source = "./subchild" +} diff --git a/terraform/test-fixtures/apply-destroy-nested-module/child/subchild/main.tf b/terraform/test-fixtures/apply-destroy-nested-module/child/subchild/main.tf new file mode 100644 index 000000000..6ff716a4d --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-nested-module/child/subchild/main.tf @@ -0,0 +1 @@ +resource "aws_instance" "bar" {} diff --git a/terraform/test-fixtures/apply-destroy-nested-module/main.tf b/terraform/test-fixtures/apply-destroy-nested-module/main.tf new file mode 100644 index 000000000..8a5a1b2e5 --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-nested-module/main.tf @@ -0,0 +1,5 @@ +/* +module "child" { + source = "./child" +} +*/ diff --git a/terraform/transform_orphan.go b/terraform/transform_orphan.go index 8e609f609..bb381c823 100644 --- a/terraform/transform_orphan.go +++ b/terraform/transform_orphan.go @@ -100,9 +100,14 @@ func (t *OrphanTransformer) Transform(g *Graph) error { moduleOrphans := t.State.ModuleOrphans(g.Path, config) moduleVertexes := make([]dag.Vertex, len(moduleOrphans)) for i, path := range moduleOrphans { + var deps []string + if s := t.State.ModuleByPath(path); s != nil { + deps = s.Dependencies + } + moduleVertexes[i] = g.Add(&graphNodeOrphanModule{ Path: path, - dependentOn: t.State.ModuleByPath(path).Dependencies, + dependentOn: deps, }) } @@ -356,3 +361,9 @@ func (n *graphNodeOrphanResourceFlat) CreateBeforeDestroy() bool { func (n *graphNodeOrphanResourceFlat) CreateNode() dag.Vertex { return n } + +func (n *graphNodeOrphanResourceFlat) ProvidedBy() []string { + return modulePrefixList( + n.graphNodeOrphanResource.ProvidedBy(), + modulePrefixStr(n.PathValue)) +} From edd05f2aa292b4e32ac19b84637d6e3c4614ff34 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 19 Jul 2015 14:14:05 -0700 Subject: [PATCH 07/48] terraform: fix some test failures --- terraform/state.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/terraform/state.go b/terraform/state.go index 520988668..511893cda 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -104,26 +104,31 @@ func (s *State) ModuleByPath(path []string) *ModuleState { // returning their full paths. These paths can be used with ModuleByPath // to return the actual state. func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { + // direct keeps track of what direct children we have both in our config + // and in our state. childrenKeys keeps track of what isn't an orphan. + direct := make(map[string]struct{}) childrenKeys := make(map[string]struct{}) if c != nil { for _, m := range c.Modules { childrenKeys[m.Name] = struct{}{} + direct[m.Name] = struct{}{} } } // Go over the direct children and find any that aren't in our keys. var orphans [][]string - direct := make(map[string]struct{}, len(childrenKeys)) for _, m := range s.Children(path) { key := m.Path[len(m.Path)-1] - if _, ok := childrenKeys[key]; ok { - continue - } // Record that we found this key as a direct child. We use this // later to find orphan nested modules. direct[key] = struct{}{} + // If we have a direct child still in our config, it is not an orphan + if _, ok := childrenKeys[key]; ok { + continue + } + orphans = append(orphans, m.Path) } @@ -140,7 +145,7 @@ func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { } // If we have the direct child, then just skip it. - key := m.Path[len(m.Path)-1] + key := m.Path[len(m.Path)-2] if _, ok := direct[key]; ok { continue } From 7735847579e777160664088b830624d0cde876e6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 19 Jul 2015 17:27:38 -0700 Subject: [PATCH 08/48] terraform: splatting with computed values is computed [GH-2744] --- terraform/interpolate.go | 5 ++ terraform/interpolate_test.go | 74 +++++++++++++++++++ .../interpolate-resource-variable/main.tf | 1 + 3 files changed, 80 insertions(+) create mode 100644 terraform/test-fixtures/interpolate-resource-variable/main.tf diff --git a/terraform/interpolate.go b/terraform/interpolate.go index 83f6265e1..40a4645f8 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -433,6 +433,11 @@ func (i *Interpolater) computeResourceMultiVariable( continue } + // If any value is unknown, the whole thing is unknown + if attr == config.UnknownVariableValue { + return config.UnknownVariableValue, nil + } + values = append(values, attr) } diff --git a/terraform/interpolate_test.go b/terraform/interpolate_test.go index 52896a54b..af06e429c 100644 --- a/terraform/interpolate_test.go +++ b/terraform/interpolate_test.go @@ -136,6 +136,80 @@ func TestInterpolater_pathRoot(t *testing.T) { }) } +func TestInterpolater_resourceVariable(t *testing.T) { + lock := new(sync.RWMutex) + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + }, + }, + } + + i := &Interpolater{ + Module: testModule(t, "interpolate-resource-variable"), + State: state, + StateLock: lock, + } + + scope := &InterpolationScope{ + Path: rootModulePath, + } + + testInterpolate(t, i, scope, "aws_instance.web.foo", ast.Variable{ + Value: "bar", + Type: ast.TypeString, + }) +} + +func TestInterpolater_resourceVariableMulti(t *testing.T) { + lock := new(sync.RWMutex) + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + Attributes: map[string]string{ + "foo": config.UnknownVariableValue, + }, + }, + }, + }, + }, + }, + } + + i := &Interpolater{ + Module: testModule(t, "interpolate-resource-variable"), + State: state, + StateLock: lock, + } + + scope := &InterpolationScope{ + Path: rootModulePath, + } + + testInterpolate(t, i, scope, "aws_instance.web.*.foo", ast.Variable{ + Value: config.UnknownVariableValue, + Type: ast.TypeString, + }) +} + func testInterpolate( t *testing.T, i *Interpolater, scope *InterpolationScope, diff --git a/terraform/test-fixtures/interpolate-resource-variable/main.tf b/terraform/test-fixtures/interpolate-resource-variable/main.tf new file mode 100644 index 000000000..64cbf6236 --- /dev/null +++ b/terraform/test-fixtures/interpolate-resource-variable/main.tf @@ -0,0 +1 @@ +resource "aws_instance" "web" {} From 392f56101c575d62fe862635633f74217d28f500 Mon Sep 17 00:00:00 2001 From: Paul Hinze Date: Mon, 20 Jul 2015 10:18:29 -0500 Subject: [PATCH 09/48] core: add failing deeply nested orphan module test I was worried about the implications of deeply nested orphaned modules in the parent commit, so I added a test. It's failing but not quite like I expected it to. Perhaps I've uncovered an unrelated bug here? /cc @mitchellh --- terraform/context_apply_test.go | 51 +++++++++++++++++++ .../child/main.tf | 3 ++ .../child/subchild/main.tf | 5 ++ .../child/subchild/subsubchild/main.tf | 1 + .../main.tf | 3 ++ 5 files changed, 63 insertions(+) create mode 100644 terraform/test-fixtures/apply-destroy-deeply-nested-module/child/main.tf create mode 100644 terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/main.tf create mode 100644 terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf create mode 100644 terraform/test-fixtures/apply-destroy-deeply-nested-module/main.tf diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 96dd8ad5c..a5e12e2d3 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -2145,6 +2145,57 @@ func TestContext2Apply_destroyNestedModule(t *testing.T) { } } +func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { + m := testModule(t, "apply-destroy-deeply-nested-module") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + s := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: []string{"root", "child", "subchild", "subsubchild"}, + Resources: map[string]*ResourceState{ + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + } + + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + State: s, + }) + + // First plan and apply a create operation + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + state, err := ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + + // Test that things were destroyed + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(` +module.child.subchild.subsubchild: + + `) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestContext2Apply_destroyOutputs(t *testing.T) { m := testModule(t, "apply-destroy-outputs") h := new(HookRecordApplyOrder) diff --git a/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/main.tf b/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/main.tf new file mode 100644 index 000000000..3694951f5 --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/main.tf @@ -0,0 +1,3 @@ +module "subchild" { + source = "./subchild" +} diff --git a/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/main.tf b/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/main.tf new file mode 100644 index 000000000..d31b87e0c --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/main.tf @@ -0,0 +1,5 @@ +/* +module "subsubchild" { + source = "./subsubchild" +} +*/ diff --git a/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf b/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf new file mode 100644 index 000000000..6ff716a4d --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-deeply-nested-module/child/subchild/subsubchild/main.tf @@ -0,0 +1 @@ +resource "aws_instance" "bar" {} diff --git a/terraform/test-fixtures/apply-destroy-deeply-nested-module/main.tf b/terraform/test-fixtures/apply-destroy-deeply-nested-module/main.tf new file mode 100644 index 000000000..1f95749fa --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-deeply-nested-module/main.tf @@ -0,0 +1,3 @@ +module "child" { + source = "./child" +} From 281e4d3e67f66daab9cdb1f7c8b6f602d949e5ee Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 08:34:41 -0700 Subject: [PATCH 10/48] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 932980236..17d120c14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ BUG FIXES: * core: Return correct number of planned updates [GH-2620] * core: Fix "provider not found" error that can occur while running a destroy plan with grandchildren modules [GH-2755] + * core: Fix UUID showing up in diff for computed splat (`foo.*.bar`) + variables. [GH-2788] * connection/ssh: fix issue on machines with an SSH Agent available preventing `key_file` from being read without explicitly setting `agent = false` [GH-2615] From 955bbbba41e9fae7f48ed54421dd5fa50568edc0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 08:41:24 -0700 Subject: [PATCH 11/48] terraform: state module orphans should only return direct --- terraform/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/state.go b/terraform/state.go index 511893cda..2ba005e39 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -145,7 +145,7 @@ func (s *State) ModuleOrphans(path []string, c *config.Config) [][]string { } // If we have the direct child, then just skip it. - key := m.Path[len(m.Path)-2] + key := m.Path[len(path)] if _, ok := direct[key]; ok { continue } From 3781f5d5bfa7d7587307b8113bf51f23a9c083e6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 08:53:16 -0700 Subject: [PATCH 12/48] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17d120c14..16c4547a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ BUG FIXES: a destroy plan with grandchildren modules [GH-2755] * core: Fix UUID showing up in diff for computed splat (`foo.*.bar`) variables. [GH-2788] + * core: Orphan modules that contain no resources (only other modules) + are properly destroyed up to arbitrary depth [GH-2786] * connection/ssh: fix issue on machines with an SSH Agent available preventing `key_file` from being read without explicitly setting `agent = false` [GH-2615] From 6550f564bf3ad8f2611c54681bdcb54b977baf76 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 17 Jul 2015 16:18:55 -0700 Subject: [PATCH 13/48] terraform: PruneNoopTransformer --- terraform/transform_noop.go | 100 +++++++++++++++++++++++++++++++ terraform/transform_noop_test.go | 54 +++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 terraform/transform_noop.go create mode 100644 terraform/transform_noop_test.go diff --git a/terraform/transform_noop.go b/terraform/transform_noop.go new file mode 100644 index 000000000..982f755ce --- /dev/null +++ b/terraform/transform_noop.go @@ -0,0 +1,100 @@ +package terraform + +import ( + "github.com/hashicorp/terraform/dag" +) + +// GraphNodeNoopPrunable can be implemented by nodes that can be +// pruned if they are noops. +type GraphNodeNoopPrunable interface { + Noop(*NoopOpts) bool +} + +// NoopOpts are the options available to determine if your node is a noop. +type NoopOpts struct { + Graph *Graph + Vertex dag.Vertex + Diff *ModuleDiff + State *ModuleState +} + +// PruneNoopTransformer is a graph transform that prunes nodes that +// consider themselves no-ops. This is done to both simplify the graph +// as well as to remove graph nodes that might otherwise cause problems +// during the graph run. Therefore, this transformer isn't completely +// an optimization step, and can instead be considered critical to +// Terraform operations. +// +// Example of the above case: variables for modules interpolate their values. +// Interpolation will fail on destruction (since attributes are being deleted), +// but variables shouldn't even eval if there is nothing that will consume +// the variable. Therefore, variables can note that they can be omitted +// safely in this case. +// +// The PruneNoopTransformer will prune nodes depth first, and will automatically +// create connect through the dependencies of pruned nodes. For example, +// if we have a graph A => B => C (A depends on B, etc.), and B decides to +// be removed, we'll still be left with A => C; the edge will be properly +// connected. +type PruneNoopTransformer struct { + Diff *Diff + State *State +} + +func (t *PruneNoopTransformer) Transform(g *Graph) error { + // Find the leaves. + leaves := make([]dag.Vertex, 0, 10) + for _, v := range g.Vertices() { + if g.DownEdges(v).Len() == 0 { + leaves = append(leaves, v) + } + } + + // Do a depth first walk from the leaves and remove things. + return g.ReverseDepthFirstWalk(leaves, func(v dag.Vertex, depth int) error { + // We need a prunable + pn, ok := v.(GraphNodeNoopPrunable) + if !ok { + return nil + } + + // Start building the noop opts + path := g.Path + if pn, ok := v.(GraphNodeSubPath); ok { + path = pn.Path() + } + + var modDiff *ModuleDiff + var modState *ModuleState + if t.Diff != nil { + modDiff = t.Diff.ModuleByPath(path) + } + if t.State != nil { + modState = t.State.ModuleByPath(path) + } + + // Determine if its a noop. If it isn't, just return + noop := pn.Noop(&NoopOpts{ + Graph: g, + Vertex: v, + Diff: modDiff, + State: modState, + }) + if !noop { + return nil + } + + // It is a noop! We first preserve edges. + up := g.UpEdges(v).List() + for _, downV := range g.DownEdges(v).List() { + for _, upV := range up { + g.Connect(dag.BasicEdge(upV, downV)) + } + } + + // Then remove it + g.Remove(v) + + return nil + }) +} diff --git a/terraform/transform_noop_test.go b/terraform/transform_noop_test.go new file mode 100644 index 000000000..65db95fda --- /dev/null +++ b/terraform/transform_noop_test.go @@ -0,0 +1,54 @@ +package terraform + +import ( + "strings" + "testing" + + "github.com/hashicorp/terraform/dag" +) + +func TestPruneNoopTransformer(t *testing.T) { + g := Graph{Path: RootModulePath} + + a := &testGraphNodeNoop{NameValue: "A"} + b := &testGraphNodeNoop{NameValue: "B", Value: true} + c := &testGraphNodeNoop{NameValue: "C"} + + g.Add(a) + g.Add(b) + g.Add(c) + g.Connect(dag.BasicEdge(a, b)) + g.Connect(dag.BasicEdge(b, c)) + + { + tf := &PruneNoopTransformer{} + if err := tf.Transform(&g); err != nil { + t.Fatalf("err: %s", err) + } + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTransformPruneNoopStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) + } +} + +const testTransformPruneNoopStr = ` +A + C +C +` + +type testGraphNodeNoop struct { + NameValue string + Value bool +} + +func (v *testGraphNodeNoop) Name() string { + return v.NameValue +} + +func (v *testGraphNodeNoop) Noop(*NoopOpts) bool { + return v.Value +} From 4d361c839eeb9697cd801a5c8198369625d6f3a6 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 17 Jul 2015 16:52:15 -0700 Subject: [PATCH 14/48] terraform: prune resources and variables --- terraform/context_apply_test.go | 43 +++++++++++++++++++ terraform/graph_builder.go | 3 ++ terraform/graph_config_node_resource.go | 32 ++++++++++++++ terraform/graph_config_node_variable.go | 22 ++++++++++ terraform/interpolate.go | 4 +- .../apply-destroy-computed/child/main.tf | 5 +++ .../apply-destroy-computed/main.tf | 6 +++ terraform/transform_noop.go | 21 +++++---- terraform/transform_root.go | 4 +- 9 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 terraform/test-fixtures/apply-destroy-computed/child/main.tf create mode 100644 terraform/test-fixtures/apply-destroy-computed/main.tf diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index a5e12e2d3..ac252abd2 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -215,6 +215,49 @@ func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { } } +func TestContext2Apply_destroyComputed(t *testing.T) { + m := testModule(t, "apply-destroy-computed") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.foo": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + Attributes: map[string]string{ + "output": "value", + }, + }, + }, + }, + }, + }, + } + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + State: state, + Destroy: true, + }) + + if p, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } else { + t.Logf(p.String()) + } + + if _, err := ctx.Apply(); err != nil { + t.Fatalf("err: %s", err) + } +} + func TestContext2Apply_minimal(t *testing.T) { m := testModule(t, "apply-minimal") p := testProvider("aws") diff --git a/terraform/graph_builder.go b/terraform/graph_builder.go index 0ec3f8b20..2190be15e 100644 --- a/terraform/graph_builder.go +++ b/terraform/graph_builder.go @@ -164,6 +164,9 @@ func (b *BuiltinGraphBuilder) Steps(path []string) []GraphTransformer { Then: &PruneDestroyTransformer{Diff: b.Diff, State: b.State}, }), + // Remove the noop nodes + &PruneNoopTransformer{Diff: b.Diff, State: b.State}, + // Insert nodes to close opened plugin connections &CloseProviderTransformer{}, &CloseProvisionerTransformer{}, diff --git a/terraform/graph_config_node_resource.go b/terraform/graph_config_node_resource.go index 2235f4925..7ddb23826 100644 --- a/terraform/graph_config_node_resource.go +++ b/terraform/graph_config_node_resource.go @@ -249,6 +249,38 @@ func (n *GraphNodeConfigResource) DestroyNode(mode GraphNodeDestroyMode) GraphNo return result } +// GraphNodeNoopPrunable +func (n *GraphNodeConfigResource) Noop(opts *NoopOpts) bool { + // We don't have any noop optimizations for destroy nodes yet + if n.DestroyMode != DestroyNone { + return false + } + + // If there is no diff, then we aren't a noop + if opts.Diff == nil || opts.Diff.Empty() { + return false + } + + // If we have no module diff, we're certainly a noop + if opts.ModDiff == nil || opts.ModDiff.Empty() { + return true + } + + // Grab the ID which is the prefix (in the case count > 0 at some point) + prefix := n.Resource.Id() + + // Go through the diff and if there are any with our name on it, keep us + found := false + for k, _ := range opts.ModDiff.Resources { + if strings.HasPrefix(k, prefix) { + found = true + break + } + } + + return !found +} + // Same as GraphNodeConfigResource, but for flattening type GraphNodeConfigResourceFlat struct { *GraphNodeConfigResource diff --git a/terraform/graph_config_node_variable.go b/terraform/graph_config_node_variable.go index 91f126c49..9b3d77dbc 100644 --- a/terraform/graph_config_node_variable.go +++ b/terraform/graph_config_node_variable.go @@ -75,6 +75,28 @@ func (n *GraphNodeConfigVariable) DestroyEdgeInclude(v dag.Vertex) bool { return false } +// GraphNodeNoopPrunable +func (n *GraphNodeConfigVariable) Noop(opts *NoopOpts) bool { + // If we have no diff, always keep this in the graph. We have to do + // this primarily for validation: we want to validate that variable + // interpolations are valid even if there are no resources that + // depend on them. + if opts.Diff == nil || opts.Diff.Empty() { + return false + } + + for _, v := range opts.Graph.UpEdges(opts.Vertex).List() { + // This is terrible, but I can't think of a better way to do this. + if dag.VertexName(v) == rootNodeName { + continue + } + + return false + } + + return true +} + // GraphNodeProxy impl. func (n *GraphNodeConfigVariable) Proxy() bool { return true diff --git a/terraform/interpolate.go b/terraform/interpolate.go index 40a4645f8..6d103cd80 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -370,7 +370,7 @@ MISSING: // be unknown. Instead, we return that the value is computed so // that the graph can continue to refresh other nodes. It doesn't // matter because the config isn't interpolated anyways. - if i.Operation == walkRefresh { + if i.Operation == walkRefresh || i.Operation == walkPlanDestroy { return config.UnknownVariableValue, nil } @@ -446,7 +446,7 @@ func (i *Interpolater) computeResourceMultiVariable( // be unknown. Instead, we return that the value is computed so // that the graph can continue to refresh other nodes. It doesn't // matter because the config isn't interpolated anyways. - if i.Operation == walkRefresh { + if i.Operation == walkRefresh || i.Operation == walkPlanDestroy { return config.UnknownVariableValue, nil } diff --git a/terraform/test-fixtures/apply-destroy-computed/child/main.tf b/terraform/test-fixtures/apply-destroy-computed/child/main.tf new file mode 100644 index 000000000..5cd1f02b6 --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-computed/child/main.tf @@ -0,0 +1,5 @@ +variable "value" {} + +resource "aws_instance" "bar" { + value = "${var.value}" +} diff --git a/terraform/test-fixtures/apply-destroy-computed/main.tf b/terraform/test-fixtures/apply-destroy-computed/main.tf new file mode 100644 index 000000000..768c9680d --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-computed/main.tf @@ -0,0 +1,6 @@ +resource "aws_instance" "foo" {} + +module "child" { + source = "./child" + value = "${aws_instance.foo.output}" +} diff --git a/terraform/transform_noop.go b/terraform/transform_noop.go index 982f755ce..95964ea1d 100644 --- a/terraform/transform_noop.go +++ b/terraform/transform_noop.go @@ -12,10 +12,12 @@ type GraphNodeNoopPrunable interface { // NoopOpts are the options available to determine if your node is a noop. type NoopOpts struct { - Graph *Graph - Vertex dag.Vertex - Diff *ModuleDiff - State *ModuleState + Graph *Graph + Vertex dag.Vertex + Diff *Diff + State *State + ModDiff *ModuleDiff + ModState *ModuleState } // PruneNoopTransformer is a graph transform that prunes nodes that @@ -52,6 +54,7 @@ func (t *PruneNoopTransformer) Transform(g *Graph) error { // Do a depth first walk from the leaves and remove things. return g.ReverseDepthFirstWalk(leaves, func(v dag.Vertex, depth int) error { + println("NAME: " + v.(dag.NamedVertex).Name()) // We need a prunable pn, ok := v.(GraphNodeNoopPrunable) if !ok { @@ -75,10 +78,12 @@ func (t *PruneNoopTransformer) Transform(g *Graph) error { // Determine if its a noop. If it isn't, just return noop := pn.Noop(&NoopOpts{ - Graph: g, - Vertex: v, - Diff: modDiff, - State: modState, + Graph: g, + Vertex: v, + Diff: t.Diff, + State: t.State, + ModDiff: modDiff, + ModState: modState, }) if !noop { return nil diff --git a/terraform/transform_root.go b/terraform/transform_root.go index 15de14754..7a422b826 100644 --- a/terraform/transform_root.go +++ b/terraform/transform_root.go @@ -2,6 +2,8 @@ package terraform import "github.com/hashicorp/terraform/dag" +const rootNodeName = "root" + // RootTransformer is a GraphTransformer that adds a root to the graph. type RootTransformer struct{} @@ -32,7 +34,7 @@ func (t *RootTransformer) Transform(g *Graph) error { type graphNodeRoot struct{} func (n graphNodeRoot) Name() string { - return "root" + return rootNodeName } func (n graphNodeRoot) Flatten(p []string) (dag.Vertex, error) { From 696d5ef94ffa48b8b0c81210dd98787502f8107d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 08:54:42 -0700 Subject: [PATCH 15/48] terraform: clarify comment --- terraform/graph_config_node_resource.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/terraform/graph_config_node_resource.go b/terraform/graph_config_node_resource.go index 7ddb23826..dfc958714 100644 --- a/terraform/graph_config_node_resource.go +++ b/terraform/graph_config_node_resource.go @@ -256,12 +256,15 @@ func (n *GraphNodeConfigResource) Noop(opts *NoopOpts) bool { return false } - // If there is no diff, then we aren't a noop + // If there is no diff, then we aren't a noop since something needs to + // be done (such as a plan). We only check if we're a noop in a diff. if opts.Diff == nil || opts.Diff.Empty() { return false } - // If we have no module diff, we're certainly a noop + // If we have no module diff, we're certainly a noop. This is because + // it means there is a diff, and that the module we're in just isn't + // in it, meaning we're not doing anything. if opts.ModDiff == nil || opts.ModDiff.Empty() { return true } From 8d29f274c8130834c790a851dab9650a67f2625b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 08:55:57 -0700 Subject: [PATCH 16/48] terraform: remove print --- terraform/transform_noop.go | 1 - 1 file changed, 1 deletion(-) diff --git a/terraform/transform_noop.go b/terraform/transform_noop.go index 95964ea1d..e36b61937 100644 --- a/terraform/transform_noop.go +++ b/terraform/transform_noop.go @@ -54,7 +54,6 @@ func (t *PruneNoopTransformer) Transform(g *Graph) error { // Do a depth first walk from the leaves and remove things. return g.ReverseDepthFirstWalk(leaves, func(v dag.Vertex, depth int) error { - println("NAME: " + v.(dag.NamedVertex).Name()) // We need a prunable pn, ok := v.(GraphNodeNoopPrunable) if !ok { From df909ca3caea08afb39102b6298496154aac34b9 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Mon, 20 Jul 2015 18:31:32 +0200 Subject: [PATCH 17/48] Fix an issue with `sudo` and `hints` Fixes issue #2781 --- .../provisioners/chef/linux_provisioner.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/builtin/provisioners/chef/linux_provisioner.go b/builtin/provisioners/chef/linux_provisioner.go index 2a1e92eab..b7a3b2813 100644 --- a/builtin/provisioners/chef/linux_provisioner.go +++ b/builtin/provisioners/chef/linux_provisioner.go @@ -71,12 +71,29 @@ func (p *Provisioner) linuxCreateConfigFiles( return err } + // Make sure we have enough rights to upload the hints if using sudo + if p.useSudo { + if err := p.runCommand(o, comm, "chmod 777 "+hintsDir); err != nil { + return err + } + } + if err := p.deployOhaiHints(o, comm, hintsDir); err != nil { return err } + + // When done copying the hints restore the rights and make sure root is owner + if p.useSudo { + if err := p.runCommand(o, comm, "chmod 755 "+hintsDir); err != nil { + return err + } + if err := p.runCommand(o, comm, "chown -R root.root "+hintsDir); err != nil { + return err + } + } } - // When done copying the files restore the rights and make sure root is owner + // When done copying all files restore the rights and make sure root is owner if p.useSudo { if err := p.runCommand(o, comm, "chmod 755 "+linuxConfDir); err != nil { return err From 885b4e9278ebe6cba8aa1b7730352a9372908db7 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Mon, 20 Jul 2015 18:34:44 +0200 Subject: [PATCH 18/48] Updating the test accordingly... --- builtin/provisioners/chef/linux_provisioner_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/builtin/provisioners/chef/linux_provisioner_test.go b/builtin/provisioners/chef/linux_provisioner_test.go index 2d509f3cb..27a1dbba0 100644 --- a/builtin/provisioners/chef/linux_provisioner_test.go +++ b/builtin/provisioners/chef/linux_provisioner_test.go @@ -163,11 +163,14 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) { }), Commands: map[string]bool{ - "sudo mkdir -p " + linuxConfDir: true, - "sudo chmod 777 " + linuxConfDir: true, - "sudo mkdir -p " + path.Join(linuxConfDir, "ohai/hints"): true, - "sudo chmod 755 " + linuxConfDir: true, - "sudo chown -R root.root " + linuxConfDir: true, + "sudo mkdir -p " + linuxConfDir: true, + "sudo chmod 777 " + linuxConfDir: true, + "sudo mkdir -p " + path.Join(linuxConfDir, "ohai/hints"): true, + "sudo chmod 777 " + path.Join(linuxConfDir, "ohai/hints"): true, + "sudo chmod 755 " + path.Join(linuxConfDir, "ohai/hints"): true, + "sudo chown -R root.root " + path.Join(linuxConfDir, "ohai/hints"): true, + "sudo chmod 755 " + linuxConfDir: true, + "sudo chown -R root.root " + linuxConfDir: true, }, Uploads: map[string]string{ From 0bd8694211ae9264b7cd19d7e1001e0290514314 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 09:36:47 -0700 Subject: [PATCH 19/48] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16c4547a0..d7f21b4cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ BUG FIXES: variables. [GH-2788] * core: Orphan modules that contain no resources (only other modules) are properly destroyed up to arbitrary depth [GH-2786] + * core: Fix "attribute not available" during destroy plans in + cases where the parameter is passed between modules [GH-2775] * connection/ssh: fix issue on machines with an SSH Agent available preventing `key_file` from being read without explicitly setting `agent = false` [GH-2615] From 670b2a722f7e0c8d91628ec486ac7b397c1d4028 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Jul 2015 09:39:04 -0700 Subject: [PATCH 20/48] Update CHANGELOG.md --- CHANGELOG.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f21b4cf..73288fb08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ FEATURES: * **New resource: `google_container_cluster`** [GH-2357] * **New resource: `aws_vpc_endpoint`** [GH-2695] +IMPROVEMENTS: + + * connection/ssh: Print SSH bastion host details to output [GH-2684] + * provider/aws: Create RDS databases from snapshots [GH-2062] + * provider/aws: Add support for restoring from Redis backup stored in S3 [GH-2634] + * provider/aws: Add `maintenance_window` to ElastiCache cluster [GH-2642] + * provider/aws: Availability Zones are optional when specifying VPC Zone Identifiers in + Auto Scaling Groups updates [GH-2724] + * provider/google: Add metadata_startup_script to google_compute_instance [GH-2375] + BUG FIXES: * core: don't prompt for variables with defaults [GH-2613] @@ -31,16 +41,7 @@ BUG FIXES: * provider/aws: `aws_route_table` ignores routes generated for VPC endpoints [GH-2695] * provider/aws: Fix issue with Launch Configurations and enable_monitoring [GH-2735] * provider/openstack: allow empty api_key and endpoint_type [GH-2626] - -IMPROVEMENTS: - - * connection/ssh: Print SSH bastion host details to output [GH-2684] - * provider/aws: Create RDS databases from snapshots [GH-2062] - * provider/aws: Add support for restoring from Redis backup stored in S3 [GH-2634] - * provider/aws: Add `maintenance_window` to ElastiCache cluster [GH-2642] - * provider/aws: Availability Zones are optional when specifying VPC Zone Identifiers in - Auto Scaling Groups updates [GH-2724] - * provider/google: Add metadata_startup_script to google_compute_instance [GH-2375] + * provisioner/chef: Fix permission denied error with ohai hints [GH-2781] ## 0.6.0 (June 30, 2015) From db5d0301d8d411a611785723d5efae5d626ca869 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 20 Jul 2015 12:32:58 -0500 Subject: [PATCH 21/48] provider/aws: Fix issue with toggling monitoring in AWS Instances --- builtin/providers/aws/resource_aws_instance.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index 9a4306acb..6d6657c15 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -579,6 +579,24 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error { } } + if d.HasChange("monitoring") { + var mErr error + if d.Get("monitoring").(bool) { + log.Printf("[DEBUG] Enabling monitoring for Instance (%s)", d.Id()) + _, mErr = conn.MonitorInstances(&ec2.MonitorInstancesInput{ + InstanceIDs: []*string{aws.String(d.Id())}, + }) + } else { + log.Printf("[DEBUG] Disabling monitoring for Instance (%s)", d.Id()) + _, mErr = conn.UnmonitorInstances(&ec2.UnmonitorInstancesInput{ + InstanceIDs: []*string{aws.String(d.Id())}, + }) + } + if mErr != nil { + return fmt.Errorf("[WARN] Error updating Instance monitoring: %s", mErr) + } + } + // TODO(mitchellh): wait for the attributes we modified to // persist the change... From a4cbef0523bafb1ce479af00af438a00e112ef41 Mon Sep 17 00:00:00 2001 From: Clint Date: Mon, 20 Jul 2015 12:38:54 -0500 Subject: [PATCH 22/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73288fb08..52739f739 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ BUG FIXES: * provider/aws: Fix issue in AWS Classic environment with referencing external Security Groups [GH-2644] * provider/aws: Bump internet gateway detach timeout [GH-2669] + * provider/aws: Fix issue with detecting differences in DB Parameters [GH-2728] * provider/aws: `ecs_cluster` rename (recreation) and deletion is handled correctly [GH-2698] * provider/aws: `aws_route_table` ignores routes generated for VPC endpoints [GH-2695] * provider/aws: Fix issue with Launch Configurations and enable_monitoring [GH-2735] From 4c67368dd85604674e1d7df0198a929d560b87e6 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 20 Jul 2015 20:03:29 +0000 Subject: [PATCH 23/48] v0.6.1 --- CHANGELOG.md | 2 +- deps/v0-6-1.json | 385 +++++++++++++++++++++++++++++++++++++++++++ terraform/version.go | 2 +- 3 files changed, 387 insertions(+), 2 deletions(-) create mode 100644 deps/v0-6-1.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 52739f739..ad3ad3065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.6.1 (Unreleased) +## 0.6.1 (July 20, 2015) FEATURES: diff --git a/deps/v0-6-1.json b/deps/v0-6-1.json new file mode 100644 index 000000000..69bbd10dc --- /dev/null +++ b/deps/v0-6-1.json @@ -0,0 +1,385 @@ +{ + "ImportPath": "github.com/hashicorp/terraform", + "GoVersion": "go1.4.2", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "code.google.com/p/go-uuid/uuid", + "Comment": "null-15", + "Rev": "35bc42037350f0078e3c974c6ea690f1926603ab" + }, + { + "ImportPath": "github.com/Azure/azure-sdk-for-go/core/http", + "Comment": "v1.2-216-g9197765", + "Rev": "91977650587a7bc48318c0430649d7fea886f111" + }, + { + "ImportPath": "github.com/Azure/azure-sdk-for-go/core/tls", + "Comment": "v1.2-216-g9197765", + "Rev": "91977650587a7bc48318c0430649d7fea886f111" + }, + { + "ImportPath": "github.com/Azure/azure-sdk-for-go/management", + "Comment": "v1.2-216-g9197765", + "Rev": "91977650587a7bc48318c0430649d7fea886f111" + }, + { + "ImportPath": "github.com/Azure/azure-sdk-for-go/storage", + "Comment": "v1.2-216-g9197765", + "Rev": "91977650587a7bc48318c0430649d7fea886f111" + }, + { + "ImportPath": "github.com/Azure/go-pkcs12", + "Rev": "a635c0684cd517745ca5c9552a312627791d5ba0" + }, + { + "ImportPath": "github.com/armon/circbuf", + "Rev": "f092b4f207b6e5cce0569056fba9e1a2735cb6cf" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/aws", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/endpoints", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/ec2query", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/json/jsonutil", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/jsonrpc", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/query", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/rest", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/restjson", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/restxml", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/internal/signer/v4", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/autoscaling", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/cloudwatch", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/dynamodb", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/ec2", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/ecs", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/elasticache", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/elb", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/iam", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/kinesis", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/lambda", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/rds", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/route53", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/s3", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/sns", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/aws/aws-sdk-go/service/sqs", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/awslabs/aws-sdk-go/aws/credentials", + "Comment": "v0.6.7-3-g2a6648c", + "Rev": "2a6648c479175ce005bca95780f948a196a46062" + }, + { + "ImportPath": "github.com/cyberdelia/heroku-go/v3", + "Rev": "594d483b9b6a8ddc7cd2f1e3e7d1de92fa2de665" + }, + { + "ImportPath": "github.com/dylanmei/iso8601", + "Rev": "2075bf119b58e5576c6ed9f867b8f3d17f2e54d4" + }, + { + "ImportPath": "github.com/dylanmei/winrmtest", + "Rev": "3e9661c52c45dab9a8528966a23d421922fca9b9" + }, + { + "ImportPath": "github.com/fsouza/go-dockerclient", + "Rev": "f6e9f5396e0e8f34472efe443d0cb7f9af162b88" + }, + { + "ImportPath": "github.com/hashicorp/atlas-go/archive", + "Comment": "20141209094003-71-g785958f", + "Rev": "785958ffcd6a8857890651f3f4d9a289ddc27633" + }, + { + "ImportPath": "github.com/hashicorp/atlas-go/v1", + "Comment": "20141209094003-71-g785958f", + "Rev": "785958ffcd6a8857890651f3f4d9a289ddc27633" + }, + { + "ImportPath": "github.com/hashicorp/consul/api", + "Comment": "v0.5.2-159-gc34bcb4", + "Rev": "c34bcb45c670af076846826ea72c436fbd0e2c35" + }, + { + "ImportPath": "github.com/hashicorp/errwrap", + "Rev": "7554cd9344cec97297fa6649b055a8c98c2a1e55" + }, + { + "ImportPath": "github.com/hashicorp/go-checkpoint", + "Rev": "88326f6851319068e7b34981032128c0b1a6524d" + }, + { + "ImportPath": "github.com/hashicorp/go-multierror", + "Rev": "56912fb08d85084aa318edcf2bba735b97cf35c5" + }, + { + "ImportPath": "github.com/hashicorp/go-version", + "Rev": "999359b6b7a041ce16e695d51e92145b83f01087" + }, + { + "ImportPath": "github.com/hashicorp/hcl", + "Rev": "54864211433d45cb780682431585b3e573b49e4a" + }, + { + "ImportPath": "github.com/hashicorp/yamux", + "Rev": "8e00b30457b1486b012f204b82ec92ae6b547de8" + }, + { + "ImportPath": "github.com/imdario/mergo", + "Comment": "0.2.0-5-g61a5285", + "Rev": "61a52852277811e93e06d28e0d0c396284a7730b" + }, + { + "ImportPath": "github.com/masterzen/simplexml/dom", + "Rev": "95ba30457eb1121fa27753627c774c7cd4e90083" + }, + { + "ImportPath": "github.com/masterzen/winrm/soap", + "Rev": "23128e7b3dc1f8091aeff7aae82cb2112ce53c75" + }, + { + "ImportPath": "github.com/masterzen/winrm/winrm", + "Rev": "23128e7b3dc1f8091aeff7aae82cb2112ce53c75" + }, + { + "ImportPath": "github.com/masterzen/xmlpath", + "Rev": "13f4951698adc0fa9c1dda3e275d489a24201161" + }, + { + "ImportPath": "github.com/mitchellh/cli", + "Rev": "8102d0ed5ea2709ade1243798785888175f6e415" + }, + { + "ImportPath": "github.com/mitchellh/colorstring", + "Rev": "61164e49940b423ba1f12ddbdf01632ac793e5e9" + }, + { + "ImportPath": "github.com/mitchellh/copystructure", + "Rev": "6fc66267e9da7d155a9d3bd489e00dad02666dc6" + }, + { + "ImportPath": "github.com/mitchellh/go-homedir", + "Rev": "1f6da4a72e57d4e7edd4a7295a585e0a3999a2d4" + }, + { + "ImportPath": "github.com/mitchellh/go-linereader", + "Rev": "07bab5fdd9580500aea6ada0e09df4aa28e68abd" + }, + { + "ImportPath": "github.com/mitchellh/mapstructure", + "Rev": "281073eb9eb092240d33ef253c404f1cca550309" + }, + { + "ImportPath": "github.com/mitchellh/osext", + "Rev": "0dd3f918b21bec95ace9dc86c7e70266cfc5c702" + }, + { + "ImportPath": "github.com/mitchellh/packer/common/uuid", + "Comment": "v0.8.2-4-g2010a0c", + "Rev": "2010a0c966175b3c0fa8d158a879c10acbba0d76" + }, + { + "ImportPath": "github.com/mitchellh/panicwrap", + "Rev": "45cbfd3bae250c7676c077fb275be1a2968e066a" + }, + { + "ImportPath": "github.com/mitchellh/prefixedio", + "Rev": "89d9b535996bf0a185f85b59578f2e245f9e1724" + }, + { + "ImportPath": "github.com/mitchellh/reflectwalk", + "Rev": "eecf4c70c626c7cfbb95c90195bc34d386c74ac6" + }, + { + "ImportPath": "github.com/nu7hatch/gouuid", + "Rev": "179d4d0c4d8d407a32af483c2354df1d2c91e6c3" + }, + { + "ImportPath": "github.com/packer-community/winrmcp/winrmcp", + "Rev": "743b1afe5ee3f6d5ba71a0d50673fa0ba2123d6b" + }, + { + "ImportPath": "github.com/pearkes/cloudflare", + "Rev": "19e280b056f3742e535ea12ae92a37ea7767ea82" + }, + { + "ImportPath": "github.com/pearkes/digitalocean", + "Rev": "e966f00c2d9de5743e87697ab77c7278f5998914" + }, + { + "ImportPath": "github.com/pearkes/dnsimple", + "Rev": "2a807d118c9e52e94819f414a6ec0293b45cad01" + }, + { + "ImportPath": "github.com/pearkes/mailgun", + "Rev": "5b02e7e9ffee9869f81393e80db138f6ff726260" + }, + { + "ImportPath": "github.com/rackspace/gophercloud", + "Comment": "v1.0.0-623-ge83aa01", + "Rev": "e83aa011e019917c7bd951444d61c42431b4d21d" + }, + { + "ImportPath": "github.com/satori/go.uuid", + "Rev": "afe1e2ddf0f05b7c29d388a3f8e76cb15c2231ca" + }, + { + "ImportPath": "github.com/soniah/dnsmadeeasy", + "Comment": "v1.1-2-g5578a8c", + "Rev": "5578a8c15e33958c61cf7db720b6181af65f4a9e" + }, + { + "ImportPath": "github.com/vaughan0/go-ini", + "Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1" + }, + { + "ImportPath": "github.com/xanzy/go-cloudstack/cloudstack", + "Comment": "v1.2.0-36-g0031956", + "Rev": "00319560eeca5e6ffef3ba048c97c126a465854f" + }, + { + "ImportPath": "golang.org/x/crypto/ssh", + "Rev": "7d5b0be716b9d6d4269afdaae10032bb296d3cdf" + }, + { + "ImportPath": "golang.org/x/net/context", + "Rev": "f0cf018861e2b54077eced91659e255072b5f215" + }, + { + "ImportPath": "golang.org/x/oauth2", + "Rev": "8914e5017ca260f2a3a1575b1e6868874050d95e" + }, + { + "ImportPath": "google.golang.org/api/compute/v1", + "Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121" + }, + { + "ImportPath": "google.golang.org/api/container/v1", + "Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121" + }, + { + "ImportPath": "google.golang.org/api/dns/v1", + "Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121" + }, + { + "ImportPath": "google.golang.org/api/googleapi", + "Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121" + }, + { + "ImportPath": "google.golang.org/api/storage/v1", + "Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121" + }, + { + "ImportPath": "google.golang.org/cloud/compute/metadata", + "Rev": "522a8ceb4bb83c2def27baccf31d646bce11a4b2" + }, + { + "ImportPath": "google.golang.org/cloud/internal", + "Rev": "522a8ceb4bb83c2def27baccf31d646bce11a4b2" + } + ] +} diff --git a/terraform/version.go b/terraform/version.go index 9cbc9adb1..8c25f6642 100644 --- a/terraform/version.go +++ b/terraform/version.go @@ -6,4 +6,4 @@ const Version = "0.6.1" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. -const VersionPrerelease = "dev" +const VersionPrerelease = "" From 71103642985b754f0ad95d6599026ab0c503792e Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 20 Jul 2015 16:03:53 -0500 Subject: [PATCH 24/48] release: clean up after v0.6.1 --- CHANGELOG.md | 2 ++ terraform/version.go | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad3ad3065..343e9477b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.6.2 (Unreleased) + ## 0.6.1 (July 20, 2015) FEATURES: diff --git a/terraform/version.go b/terraform/version.go index 8c25f6642..78f3e5ff7 100644 --- a/terraform/version.go +++ b/terraform/version.go @@ -1,9 +1,9 @@ package terraform // The main version number that is being run at the moment. -const Version = "0.6.1" +const Version = "0.6.2" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. -const VersionPrerelease = "" +const VersionPrerelease = "dev" From dfbe7bee9e00e68f1ec62a583fd3ac6024d3e03b Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 21 Jul 2015 08:36:27 -0500 Subject: [PATCH 25/48] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 343e9477b..9480c2086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.6.2 (Unreleased) +IMPROVEMENTS: + + * provider/aws: Validate credentials before walking the graph [GH-2730] + ## 0.6.1 (July 20, 2015) FEATURES: From 4797a82e1ad3424c4dfd394f3b9857fa8581aa80 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 21 Jul 2015 15:57:59 +0200 Subject: [PATCH 26/48] aws: Simplify ValidateCredentials func --- builtin/providers/aws/config.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index a1a0dd361..f58938285 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -174,16 +174,14 @@ func (c *Config) ValidateRegion() error { // Validate credentials early and fail before we do any graph walking func (c *Config) ValidateCredentials(iamconn *iam.IAM) error { _, err := iamconn.GetUser(nil) - if err != nil { - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "SignatureDoesNotMatch" { - return fmt.Errorf("Failed authenticating with AWS: please verify credentials") - } + + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "SignatureDoesNotMatch" { + return fmt.Errorf("Failed authenticating with AWS: please verify credentials") } - return err } - return nil + return err } // ValidateAccountId returns a context-specific error if the configured account From 3688d4ba0086f919a528ef166a4a4bb3262341a6 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 21 Jul 2015 09:42:02 -0500 Subject: [PATCH 27/48] provider/aws: Converge on TestAccAWS for acceptance tests names An attempt to converge the tests into a standard naming scheme - TestAccAWS for aws tests - a `_basic` test for each suite, save a few that are quick (Network ACLs, for example) --- .../aws/resource_aws_customer_gateway_test.go | 2 +- .../providers/aws/resource_aws_flow_log_test.go | 4 ++-- .../resource_aws_iam_server_certificate_test.go | 2 +- .../aws/resource_aws_kinesis_stream_test.go | 2 +- .../aws/resource_aws_lambda_function_test.go | 2 +- .../resource_aws_route53_delegation_set_test.go | 4 ++-- .../resource_aws_route53_health_check_test.go | 4 ++-- .../aws/resource_aws_route53_record_test.go | 16 ++++++++-------- ...resource_aws_route53_zone_association_test.go | 4 ++-- .../aws/resource_aws_route53_zone_test.go | 6 +++--- .../aws/resource_aws_vpc_dhcp_options_test.go | 2 +- .../aws/resource_aws_vpc_endpoint_test.go | 4 ++-- builtin/providers/aws/resource_aws_vpc_test.go | 10 +++++----- .../aws/resource_aws_vpn_gateway_test.go | 2 +- 14 files changed, 32 insertions(+), 32 deletions(-) diff --git a/builtin/providers/aws/resource_aws_customer_gateway_test.go b/builtin/providers/aws/resource_aws_customer_gateway_test.go index 33e370946..9e3daec6d 100644 --- a/builtin/providers/aws/resource_aws_customer_gateway_test.go +++ b/builtin/providers/aws/resource_aws_customer_gateway_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccCustomerGateway_basic(t *testing.T) { +func TestAccAWSCustomerGateway_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, diff --git a/builtin/providers/aws/resource_aws_flow_log_test.go b/builtin/providers/aws/resource_aws_flow_log_test.go index b938a6fea..a7dd9ad32 100644 --- a/builtin/providers/aws/resource_aws_flow_log_test.go +++ b/builtin/providers/aws/resource_aws_flow_log_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccFlowLog_basic(t *testing.T) { +func TestAccAWSFlowLog_basic(t *testing.T) { var flowLog ec2.FlowLog lgn := os.Getenv("LOG_GROUP_NAME") @@ -31,7 +31,7 @@ func TestAccFlowLog_basic(t *testing.T) { }) } -func TestAccFlowLog_subnet(t *testing.T) { +func TestAccAWSFlowLog_subnet(t *testing.T) { var flowLog ec2.FlowLog lgn := os.Getenv("LOG_GROUP_NAME") diff --git a/builtin/providers/aws/resource_aws_iam_server_certificate_test.go b/builtin/providers/aws/resource_aws_iam_server_certificate_test.go index 3165416fc..5982a8b6c 100644 --- a/builtin/providers/aws/resource_aws_iam_server_certificate_test.go +++ b/builtin/providers/aws/resource_aws_iam_server_certificate_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccIAMServerCertificate_basic(t *testing.T) { +func TestAccAWSIAMServerCertificate_basic(t *testing.T) { var cert iam.ServerCertificate resource.Test(t, resource.TestCase{ diff --git a/builtin/providers/aws/resource_aws_kinesis_stream_test.go b/builtin/providers/aws/resource_aws_kinesis_stream_test.go index 01d14d3d0..814ea92d2 100644 --- a/builtin/providers/aws/resource_aws_kinesis_stream_test.go +++ b/builtin/providers/aws/resource_aws_kinesis_stream_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccKinesisStream_basic(t *testing.T) { +func TestAccAWSKinesisStream_basic(t *testing.T) { var stream kinesis.StreamDescription resource.Test(t, resource.TestCase{ diff --git a/builtin/providers/aws/resource_aws_lambda_function_test.go b/builtin/providers/aws/resource_aws_lambda_function_test.go index d85bd7e8d..12edb99e0 100644 --- a/builtin/providers/aws/resource_aws_lambda_function_test.go +++ b/builtin/providers/aws/resource_aws_lambda_function_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccAWSLambdaFunction_normal(t *testing.T) { +func TestAccAWSLambdaFunction_basic(t *testing.T) { var conf lambda.GetFunctionOutput resource.Test(t, resource.TestCase{ diff --git a/builtin/providers/aws/resource_aws_route53_delegation_set_test.go b/builtin/providers/aws/resource_aws_route53_delegation_set_test.go index 8de0e1b83..f9bf3cd87 100644 --- a/builtin/providers/aws/resource_aws_route53_delegation_set_test.go +++ b/builtin/providers/aws/resource_aws_route53_delegation_set_test.go @@ -13,7 +13,7 @@ import ( "github.com/aws/aws-sdk-go/service/route53" ) -func TestAccRoute53DelegationSet_basic(t *testing.T) { +func TestAccAWSRoute53DelegationSet_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -29,7 +29,7 @@ func TestAccRoute53DelegationSet_basic(t *testing.T) { }) } -func TestAccRoute53DelegationSet_withZones(t *testing.T) { +func TestAccAWSRoute53DelegationSet_withZones(t *testing.T) { var zone route53.GetHostedZoneOutput resource.Test(t, resource.TestCase{ diff --git a/builtin/providers/aws/resource_aws_route53_health_check_test.go b/builtin/providers/aws/resource_aws_route53_health_check_test.go index 32286cc41..e27de56d4 100644 --- a/builtin/providers/aws/resource_aws_route53_health_check_test.go +++ b/builtin/providers/aws/resource_aws_route53_health_check_test.go @@ -10,7 +10,7 @@ import ( "github.com/aws/aws-sdk-go/service/route53" ) -func TestAccRoute53HealthCheck_basic(t *testing.T) { +func TestAccAWSRoute53HealthCheck_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -34,7 +34,7 @@ func TestAccRoute53HealthCheck_basic(t *testing.T) { }) } -func TestAccRoute53HealthCheck_IpConfig(t *testing.T) { +func TestAccAWSRoute53HealthCheck_IpConfig(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, diff --git a/builtin/providers/aws/resource_aws_route53_record_test.go b/builtin/providers/aws/resource_aws_route53_record_test.go index eaa6abb7a..08f824ccb 100644 --- a/builtin/providers/aws/resource_aws_route53_record_test.go +++ b/builtin/providers/aws/resource_aws_route53_record_test.go @@ -50,7 +50,7 @@ func TestExpandRecordName(t *testing.T) { } } -func TestAccRoute53Record_basic(t *testing.T) { +func TestAccAWSRoute53Record_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -66,7 +66,7 @@ func TestAccRoute53Record_basic(t *testing.T) { }) } -func TestAccRoute53Record_txtSupport(t *testing.T) { +func TestAccAWSRoute53Record_txtSupport(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -82,7 +82,7 @@ func TestAccRoute53Record_txtSupport(t *testing.T) { }) } -func TestAccRoute53Record_generatesSuffix(t *testing.T) { +func TestAccAWSRoute53Record_generatesSuffix(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -98,7 +98,7 @@ func TestAccRoute53Record_generatesSuffix(t *testing.T) { }) } -func TestAccRoute53Record_wildcard(t *testing.T) { +func TestAccAWSRoute53Record_wildcard(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -122,7 +122,7 @@ func TestAccRoute53Record_wildcard(t *testing.T) { }) } -func TestAccRoute53Record_weighted(t *testing.T) { +func TestAccAWSRoute53Record_weighted(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -139,7 +139,7 @@ func TestAccRoute53Record_weighted(t *testing.T) { }) } -func TestAccRoute53Record_alias(t *testing.T) { +func TestAccAWSRoute53Record_alias(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -155,7 +155,7 @@ func TestAccRoute53Record_alias(t *testing.T) { }) } -func TestAccRoute53Record_weighted_alias(t *testing.T) { +func TestAccAWSRoute53Record_weighted_alias(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -182,7 +182,7 @@ func TestAccRoute53Record_weighted_alias(t *testing.T) { }) } -func TestAccRoute53Record_TypeChange(t *testing.T) { +func TestAccAWSRoute53Record_TypeChange(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, diff --git a/builtin/providers/aws/resource_aws_route53_zone_association_test.go b/builtin/providers/aws/resource_aws_route53_zone_association_test.go index e929d4d31..b04b3bb51 100644 --- a/builtin/providers/aws/resource_aws_route53_zone_association_test.go +++ b/builtin/providers/aws/resource_aws_route53_zone_association_test.go @@ -12,7 +12,7 @@ import ( "github.com/aws/aws-sdk-go/service/route53" ) -func TestAccRoute53ZoneAssociation_basic(t *testing.T) { +func TestAccAWSRoute53ZoneAssociation_basic(t *testing.T) { var zone route53.HostedZone resource.Test(t, resource.TestCase{ @@ -30,7 +30,7 @@ func TestAccRoute53ZoneAssociation_basic(t *testing.T) { }) } -func TestAccRoute53ZoneAssociation_region(t *testing.T) { +func TestAccAWSRoute53ZoneAssociation_region(t *testing.T) { var zone route53.HostedZone // record the initialized providers so that we can use them to diff --git a/builtin/providers/aws/resource_aws_route53_zone_test.go b/builtin/providers/aws/resource_aws_route53_zone_test.go index 92ab8a217..4fa1d51a8 100644 --- a/builtin/providers/aws/resource_aws_route53_zone_test.go +++ b/builtin/providers/aws/resource_aws_route53_zone_test.go @@ -64,7 +64,7 @@ func TestCleanChangeID(t *testing.T) { } } -func TestAccRoute53Zone_basic(t *testing.T) { +func TestAccAWSRoute53Zone_basic(t *testing.T) { var zone route53.GetHostedZoneOutput var td route53.ResourceTagSet @@ -85,7 +85,7 @@ func TestAccRoute53Zone_basic(t *testing.T) { }) } -func TestAccRoute53Zone_private_basic(t *testing.T) { +func TestAccAWSRoute53Zone_private_basic(t *testing.T) { var zone route53.GetHostedZoneOutput resource.Test(t, resource.TestCase{ @@ -104,7 +104,7 @@ func TestAccRoute53Zone_private_basic(t *testing.T) { }) } -func TestAccRoute53Zone_private_region(t *testing.T) { +func TestAccAWSRoute53Zone_private_region(t *testing.T) { var zone route53.GetHostedZoneOutput // record the initialized providers so that we can use them to diff --git a/builtin/providers/aws/resource_aws_vpc_dhcp_options_test.go b/builtin/providers/aws/resource_aws_vpc_dhcp_options_test.go index 988c8b3c4..e47f4d89d 100644 --- a/builtin/providers/aws/resource_aws_vpc_dhcp_options_test.go +++ b/builtin/providers/aws/resource_aws_vpc_dhcp_options_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccDHCPOptions_basic(t *testing.T) { +func TestAccAWSDHCPOptions_basic(t *testing.T) { var d ec2.DHCPOptions resource.Test(t, resource.TestCase{ diff --git a/builtin/providers/aws/resource_aws_vpc_endpoint_test.go b/builtin/providers/aws/resource_aws_vpc_endpoint_test.go index 6a29b688e..3d3055494 100644 --- a/builtin/providers/aws/resource_aws_vpc_endpoint_test.go +++ b/builtin/providers/aws/resource_aws_vpc_endpoint_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccVpcEndpoint_basic(t *testing.T) { +func TestAccAWSVpcEndpoint_basic(t *testing.T) { var endpoint ec2.VPCEndpoint resource.Test(t, resource.TestCase{ @@ -29,7 +29,7 @@ func TestAccVpcEndpoint_basic(t *testing.T) { }) } -func TestAccVpcEndpoint_withRouteTableAndPolicy(t *testing.T) { +func TestAccAWSVpcEndpoint_withRouteTableAndPolicy(t *testing.T) { var endpoint ec2.VPCEndpoint var routeTable ec2.RouteTable diff --git a/builtin/providers/aws/resource_aws_vpc_test.go b/builtin/providers/aws/resource_aws_vpc_test.go index 95121ec6f..a55fc2af7 100644 --- a/builtin/providers/aws/resource_aws_vpc_test.go +++ b/builtin/providers/aws/resource_aws_vpc_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccVpc_basic(t *testing.T) { +func TestAccAWSVpc_basic(t *testing.T) { var vpc ec2.VPC resource.Test(t, resource.TestCase{ @@ -32,7 +32,7 @@ func TestAccVpc_basic(t *testing.T) { }) } -func TestAccVpc_dedicatedTenancy(t *testing.T) { +func TestAccAWSVpc_dedicatedTenancy(t *testing.T) { var vpc ec2.VPC resource.Test(t, resource.TestCase{ @@ -52,7 +52,7 @@ func TestAccVpc_dedicatedTenancy(t *testing.T) { }) } -func TestAccVpc_tags(t *testing.T) { +func TestAccAWSVpc_tags(t *testing.T) { var vpc ec2.VPC resource.Test(t, resource.TestCase{ @@ -83,7 +83,7 @@ func TestAccVpc_tags(t *testing.T) { }) } -func TestAccVpcUpdate(t *testing.T) { +func TestAccAWSVpc_update(t *testing.T) { var vpc ec2.VPC resource.Test(t, resource.TestCase{ @@ -187,7 +187,7 @@ func testAccCheckVpcExists(n string, vpc *ec2.VPC) resource.TestCheckFunc { } // https://github.com/hashicorp/terraform/issues/1301 -func TestAccVpc_bothDnsOptionsSet(t *testing.T) { +func TestAccAWSVpc_bothDnsOptionsSet(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, diff --git a/builtin/providers/aws/resource_aws_vpn_gateway_test.go b/builtin/providers/aws/resource_aws_vpn_gateway_test.go index 6b1d3fc48..c39970c93 100644 --- a/builtin/providers/aws/resource_aws_vpn_gateway_test.go +++ b/builtin/providers/aws/resource_aws_vpn_gateway_test.go @@ -87,7 +87,7 @@ func TestAccAWSVpnGateway_delete(t *testing.T) { }) } -func TestAccVpnGateway_tags(t *testing.T) { +func TestAccAWSVpnGateway_tags(t *testing.T) { var v ec2.VPNGateway resource.Test(t, resource.TestCase{ From ce204a89bba37af6bfe5fb812092526d018d1fd7 Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 21 Jul 2015 10:23:28 -0500 Subject: [PATCH 28/48] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9480c2086..08fe190d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ IMPROVEMENTS: * provider/aws: Validate credentials before walking the graph [GH-2730] +BUG FIXES: + + * provider/aws: Fix issue with toggling monitoring in AWS Instances [GH-2794] + ## 0.6.1 (July 20, 2015) FEATURES: From 87239dcec89fd3b518513cbedf77ed5eb19bac04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Naveiras?= Date: Tue, 21 Jul 2015 17:18:50 +0200 Subject: [PATCH 29/48] Amend AWS spot instace state name cancelled --- builtin/providers/aws/resource_aws_spot_instance_request.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_spot_instance_request.go b/builtin/providers/aws/resource_aws_spot_instance_request.go index 464a3de0c..bed4c42cb 100644 --- a/builtin/providers/aws/resource_aws_spot_instance_request.go +++ b/builtin/providers/aws/resource_aws_spot_instance_request.go @@ -160,7 +160,7 @@ func resourceAwsSpotInstanceRequestRead(d *schema.ResourceData, meta interface{} request := resp.SpotInstanceRequests[0] // if the request is cancelled, then it is gone - if *request.State == "canceled" { + if *request.State == "cancelled" { d.SetId("") return nil } From 90c3e06628268cd1a133679f30d12310d550dc0b Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 21 Jul 2015 10:44:19 -0500 Subject: [PATCH 30/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08fe190d3..9aeb0bc69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ IMPROVEMENTS: BUG FIXES: * provider/aws: Fix issue with toggling monitoring in AWS Instances [GH-2794] + * provider/aws: Fix issue with Spot Instance Requests and cancellation [GH-2805] ## 0.6.1 (July 20, 2015) From b720387449969ddf2a8ad64d93060fa1cce2d45f Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 21 Jul 2015 11:13:41 -0500 Subject: [PATCH 31/48] provider/aws: Clean up externally removed Launch Configurations Handle Launch Configurations that are not found more gracefully, but tolerating an additional API error indicating the LC no longer exists. --- builtin/providers/aws/resource_aws_launch_configuration.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_launch_configuration.go b/builtin/providers/aws/resource_aws_launch_configuration.go index ab6350b38..85630aa5a 100644 --- a/builtin/providers/aws/resource_aws_launch_configuration.go +++ b/builtin/providers/aws/resource_aws_launch_configuration.go @@ -480,7 +480,8 @@ func resourceAwsLaunchConfigurationDelete(d *schema.ResourceData, meta interface }) if err != nil { autoscalingerr, ok := err.(awserr.Error) - if ok && autoscalingerr.Code() == "InvalidConfiguration.NotFound" { + if ok && (autoscalingerr.Code() == "InvalidConfiguration.NotFound" || autoscalingerr.Code() == "ValidationError") { + log.Printf("[DEBUG] Launch configuration (%s) not found", d.Id()) return nil } From 9cb3150535b81f82d702e029ed395917c8ec8a11 Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 21 Jul 2015 15:53:33 -0500 Subject: [PATCH 32/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aeb0bc69..4a3386d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ IMPROVEMENTS: * provider/aws: Validate credentials before walking the graph [GH-2730] + * provider/aws: ELB names are now optional, and generated by Terraform if omitted [GH-2571] BUG FIXES: From 7a60174dd170c43e35aa2fb1dd0201512bc72d16 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Wed, 22 Jul 2015 12:49:05 +0200 Subject: [PATCH 33/48] Do not print errors via UiHook --- command/hook_ui.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/command/hook_ui.go b/command/hook_ui.go index c9543b3f6..6a10ceefb 100644 --- a/command/hook_ui.go +++ b/command/hook_ui.go @@ -140,7 +140,8 @@ func (h *UiHook) PostApply( } if applyerr != nil { - msg = fmt.Sprintf("Error: %s", applyerr) + // Errors are collected and printed in ApplyCommand, no need to duplicate + return terraform.HookActionContinue, nil } h.ui.Output(h.Colorize.Color(fmt.Sprintf( From 8e477b78d83860c07f168f5dcec8670d938d4b8f Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Wed, 22 Jul 2015 12:50:06 +0200 Subject: [PATCH 34/48] Add resource ID to errors coming from apply --- terraform/eval_apply.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/terraform/eval_apply.go b/terraform/eval_apply.go index cebf68265..c22a6ca4e 100644 --- a/terraform/eval_apply.go +++ b/terraform/eval_apply.go @@ -94,7 +94,8 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) { // if we have one, otherwise we just output it. if err != nil { if n.Error != nil { - *n.Error = multierror.Append(*n.Error, err) + helpfulErr := fmt.Errorf("%s: %s", n.Info.Id, err.Error()) + *n.Error = multierror.Append(*n.Error, helpfulErr) } else { return nil, err } From a22dc2a9a2c63fceaa23be564478243eb6f641ac Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Wed, 22 Jul 2015 13:51:14 +0200 Subject: [PATCH 35/48] Add resource ID to refresh errors --- terraform/eval_refresh.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/terraform/eval_refresh.go b/terraform/eval_refresh.go index 3d25ecc8b..fa2b8126c 100644 --- a/terraform/eval_refresh.go +++ b/terraform/eval_refresh.go @@ -1,6 +1,7 @@ package terraform import ( + "fmt" "log" ) @@ -35,7 +36,7 @@ func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) { // Refresh! state, err = provider.Refresh(n.Info, state) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %s", n.Info.Id, err.Error()) } // Call post-refresh hook From cbe9be4571f89295397cb57b3bf452695cf2dd18 Mon Sep 17 00:00:00 2001 From: John Engelman Date: Wed, 3 Jun 2015 10:10:17 -0500 Subject: [PATCH 36/48] Add website_domain for S3 buckets. --- .../aws/resource_aws_route53_record_test.go | 42 +++++++++++++++++++ .../providers/aws/resource_aws_s3_bucket.go | 40 +++++++++++++----- .../aws/website_endpoint_url_test.go | 6 +-- .../providers/aws/r/s3_bucket.html.markdown | 1 + 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/builtin/providers/aws/resource_aws_route53_record_test.go b/builtin/providers/aws/resource_aws_route53_record_test.go index 08f824ccb..0435dffb1 100644 --- a/builtin/providers/aws/resource_aws_route53_record_test.go +++ b/builtin/providers/aws/resource_aws_route53_record_test.go @@ -155,6 +155,22 @@ func TestAccAWSRoute53Record_alias(t *testing.T) { }) } +func TestAccAWSRoute53Record_s3_alias(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53RecordDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccRoute53S3AliasRecord, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53RecordExists("aws_route53_record.alias"), + ), + }, + }, + }) +} + func TestAccAWSRoute53Record_weighted_alias(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -449,6 +465,32 @@ resource "aws_route53_record" "alias" { } ` +const testAccRoute53S3AliasRecord = ` +resource "aws_route53_zone" "main" { + name = "notexample.com" +} + +resource "aws_s3_bucket" "website" { + bucket = "website.notexample.com" + acl = "public-read" + website { + index_document = "index.html" + } +} + +resource "aws_route53_record" "alias" { + zone_id = "${aws_route53_zone.main.zone_id}" + name = "www" + type = "A" + + alias { + zone_id = "${aws_s3_bucket.website.hosted_zone_id}" + name = "${aws_s3_bucket.website.website_domain}" + evaluate_target_health = true + } +} +` + const testAccRoute53WeightedElbAliasRecord = ` resource "aws_route53_zone" "main" { name = "notexample.com" diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index 93bf24390..af60e2214 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -77,12 +77,16 @@ func resourceAwsS3Bucket() *schema.Resource { Optional: true, Computed: true, }, - "website_endpoint": &schema.Schema{ Type: schema.TypeString, Optional: true, Computed: true, }, + "website_domain": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "tags": tagsSchema(), @@ -237,12 +241,17 @@ func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error { } // Add website_endpoint as an attribute - endpoint, err := websiteEndpoint(s3conn, d) + websiteEndpoint, err := websiteEndpoint(s3conn, d) if err != nil { return err } - if err := d.Set("website_endpoint", endpoint); err != nil { - return err + if websiteEndpoint != nil { + if err := d.Set("website_endpoint", websiteEndpoint.Endpoint); err != nil { + return err + } + if err := d.Set("website_domain", websiteEndpoint.Domain); err != nil { + return err + } } tagSet, err := getTagSetS3(s3conn, d.Id()) @@ -405,11 +414,11 @@ func resourceAwsS3BucketWebsiteDelete(s3conn *s3.S3, d *schema.ResourceData) err return nil } -func websiteEndpoint(s3conn *s3.S3, d *schema.ResourceData) (string, error) { +func websiteEndpoint(s3conn *s3.S3, d *schema.ResourceData) (*S3Website, error) { // If the bucket doesn't have a website configuration, return an empty // endpoint if _, ok := d.GetOk("website"); !ok { - return "", nil + return nil, nil } bucket := d.Get("bucket").(string) @@ -421,26 +430,31 @@ func websiteEndpoint(s3conn *s3.S3, d *schema.ResourceData) (string, error) { }, ) if err != nil { - return "", err + return nil, err } var region string if location.LocationConstraint != nil { region = *location.LocationConstraint } - return WebsiteEndpointUrl(bucket, region), nil + return WebsiteEndpoint(bucket, region), nil } -func WebsiteEndpointUrl(bucket string, region string) string { +func WebsiteEndpoint(bucket string, region string) *S3Website { + domain := WebsiteDomainUrl(region) + return &S3Website{Endpoint: fmt.Sprintf("%s.%s", bucket, domain), Domain: domain} +} + +func WebsiteDomainUrl(region string) string { region = normalizeRegion(region) // Frankfurt(and probably future) regions uses different syntax for website endpoints // http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html if region == "eu-central-1" { - return fmt.Sprintf("%s.s3-website.%s.amazonaws.com", bucket, region) + return fmt.Sprintf("s3-website.%s.amazonaws.com", region) } - return fmt.Sprintf("%s.s3-website-%s.amazonaws.com", bucket, region) + return fmt.Sprintf("s3-website-%s.amazonaws.com", region) } func normalizeJson(jsonString interface{}) string { @@ -465,3 +479,7 @@ func normalizeRegion(region string) string { return region } + +type S3Website struct { + Endpoint, Domain string +} diff --git a/builtin/providers/aws/website_endpoint_url_test.go b/builtin/providers/aws/website_endpoint_url_test.go index 2f4ce5249..bbe282e2c 100644 --- a/builtin/providers/aws/website_endpoint_url_test.go +++ b/builtin/providers/aws/website_endpoint_url_test.go @@ -20,9 +20,9 @@ var websiteEndpoints = []struct { func TestWebsiteEndpointUrl(t *testing.T) { for _, tt := range websiteEndpoints { - s := WebsiteEndpointUrl("bucket-name", tt.in) - if s != tt.out { - t.Errorf("WebsiteEndpointUrl(\"bucket-name\", %q) => %q, want %q", tt.in, s, tt.out) + s := WebsiteEndpoint("bucket-name", tt.in) + if s.Endpoint != tt.out { + t.Errorf("WebsiteEndpointUrl(\"bucket-name\", %q) => %q, want %q", tt.in, s.Endpoint, tt.out) } } } diff --git a/website/source/docs/providers/aws/r/s3_bucket.html.markdown b/website/source/docs/providers/aws/r/s3_bucket.html.markdown index 4f367d4f8..f30c153c5 100644 --- a/website/source/docs/providers/aws/r/s3_bucket.html.markdown +++ b/website/source/docs/providers/aws/r/s3_bucket.html.markdown @@ -67,3 +67,4 @@ The following attributes are exported: * `hosted_zone_id` - The [Route 53 Hosted Zone ID](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_website_region_endpoints) for this bucket's region. * `region` - The AWS region this bucket resides in. * `website_endpoint` - The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. +* `website_domain` - The domain of the website endpoint, if the bucket is configured with a website. If not, this will be an empty string. This is used to create Route 53 alias records. From 78eb236786a418ec78bfc413418cbec791606688 Mon Sep 17 00:00:00 2001 From: Clint Date: Wed, 22 Jul 2015 11:06:31 -0500 Subject: [PATCH 37/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a3386d3f..159240163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ IMPROVEMENTS: * provider/aws: Validate credentials before walking the graph [GH-2730] + * provider/aws: Add website_domain for S3 buckets [GH-2210] * provider/aws: ELB names are now optional, and generated by Terraform if omitted [GH-2571] BUG FIXES: From 761c8ab225e180dff207fc0ba943496e63ce4a6d Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Wed, 22 Jul 2015 20:59:45 +0200 Subject: [PATCH 38/48] Fix link in the docs --- website/source/layouts/cloudstack.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/layouts/cloudstack.erb b/website/source/layouts/cloudstack.erb index 1cf60b787..84c52e2df 100644 --- a/website/source/layouts/cloudstack.erb +++ b/website/source/layouts/cloudstack.erb @@ -54,7 +54,7 @@ > - cloudstack_secondary_ipaddress + cloudstack_secondary_ipaddress > From 5554942721ec71c4a42d5c305d9c02a4361e3a0c Mon Sep 17 00:00:00 2001 From: Jesse Szwedko Date: Wed, 15 Jul 2015 18:42:32 +0000 Subject: [PATCH 39/48] This adds the source_dest_check attribute to the aws_network_interface resource Defaults to true to be consistent with AWS --- .../aws/resource_aws_network_interface.go | 19 +++++++++ .../resource_aws_network_interface_test.go | 42 +++++++++++++++++++ .../aws/r/network_interface.markdown | 2 + 3 files changed, 63 insertions(+) diff --git a/builtin/providers/aws/resource_aws_network_interface.go b/builtin/providers/aws/resource_aws_network_interface.go index aee50f0aa..2cf7b13c3 100644 --- a/builtin/providers/aws/resource_aws_network_interface.go +++ b/builtin/providers/aws/resource_aws_network_interface.go @@ -46,6 +46,12 @@ func resourceAwsNetworkInterface() *schema.Resource { Set: schema.HashString, }, + "source_dest_check": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "attachment": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -127,6 +133,7 @@ func resourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) e d.Set("subnet_id", eni.SubnetID) d.Set("private_ips", flattenNetworkInterfacesPrivateIPAddesses(eni.PrivateIPAddresses)) d.Set("security_groups", flattenGroupIdentifiers(eni.Groups)) + d.Set("source_dest_check", eni.SourceDestCheck) // Tags d.Set("tags", tagsToMap(eni.TagSet)) @@ -221,6 +228,18 @@ func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) d.SetPartial("attachment") } + request := &ec2.ModifyNetworkInterfaceAttributeInput{ + NetworkInterfaceID: aws.String(d.Id()), + SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Boolean(d.Get("source_dest_check").(bool))}, + } + + _, err := conn.ModifyNetworkInterfaceAttribute(request) + if err != nil { + return fmt.Errorf("Failure updating ENI: %s", err) + } + + d.SetPartial("source_dest_check") + if d.HasChange("security_groups") { request := &ec2.ModifyNetworkInterfaceAttributeInput{ NetworkInterfaceID: aws.String(d.Id()), diff --git a/builtin/providers/aws/resource_aws_network_interface_test.go b/builtin/providers/aws/resource_aws_network_interface_test.go index f83698abf..a444a0136 100644 --- a/builtin/providers/aws/resource_aws_network_interface_test.go +++ b/builtin/providers/aws/resource_aws_network_interface_test.go @@ -57,6 +57,26 @@ func TestAccAWSENI_attached(t *testing.T) { }) } +func TestAccAWSENI_sourceDestCheck(t *testing.T) { + var conf ec2.NetworkInterface + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSENIDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSENIConfigWithSourceDestCheck, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSENIExists("aws_network_interface.bar", &conf), + resource.TestCheckResourceAttr( + "aws_network_interface.bar", "source_dest_check", "false"), + ), + }, + }, + }) +} + func testAccCheckAWSENIExists(n string, res *ec2.NetworkInterface) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -108,6 +128,10 @@ func testAccCheckAWSENIAttributes(conf *ec2.NetworkInterface) resource.TestCheck return fmt.Errorf("expected private ip to be 172.16.10.100, but was %s", *conf.PrivateIPAddress) } + if *conf.SourceDestCheck != true { + return fmt.Errorf("expected source_dest_check to be true, but was %t", *conf.SourceDestCheck) + } + if len(conf.TagSet) == 0 { return fmt.Errorf("expected tags") } @@ -201,6 +225,24 @@ resource "aws_network_interface" "bar" { } ` +const testAccAWSENIConfigWithSourceDestCheck = ` +resource "aws_vpc" "foo" { + cidr_block = "172.16.0.0/16" +} + +resource "aws_subnet" "foo" { + vpc_id = "${aws_vpc.foo.id}" + cidr_block = "172.16.10.0/24" + availability_zone = "us-west-2a" +} + +resource "aws_network_interface" "bar" { + subnet_id = "${aws_subnet.foo.id}" + source_dest_check = false + private_ips = ["172.16.10.100"] +} +` + const testAccAWSENIConfigWithAttachment = ` resource "aws_vpc" "foo" { cidr_block = "172.16.0.0/16" diff --git a/website/source/docs/providers/aws/r/network_interface.markdown b/website/source/docs/providers/aws/r/network_interface.markdown index 8144d8f0f..0384b184a 100644 --- a/website/source/docs/providers/aws/r/network_interface.markdown +++ b/website/source/docs/providers/aws/r/network_interface.markdown @@ -32,6 +32,7 @@ The following arguments are supported: * `private_ips` - (Optional) List of private IPs to assign to the ENI. * `security_groups` - (Optional) List of security group IDs to assign to the ENI. * `attachment` - (Required) Block to define the attachment of the ENI. Documented below. +* `source_dest_check` - (Optional) Whether to enable source destination checking for the ENI. Default true. * `tags` - (Optional) A mapping of tags to assign to the resource. The `attachment` block supports: @@ -47,5 +48,6 @@ The following attributes are exported: * `private_ips` - List of private IPs assigned to the ENI. * `security_groups` - List of security groups attached to the ENI. * `attachment` - Block defining the attachment of the ENI. +* `source_dest_check` - Whether source destination checking is enabled * `tags` - Tags assigned to the ENI. From 7092b8ba8a341f842d1fe9c441b27edad5affe55 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 23 Jul 2015 01:01:13 -0700 Subject: [PATCH 40/48] Split AWS provider topics by service. With so many AWS provider resources, the docs are getting pretty hard to navigate. This is particularly true due to the mismatch of some resources encoding the service name (like aws_route53_record) but some others ignoring it (like aws_subnet) or using a generic prefix (like aws_db_instance), which causes an alphabetical ordering to muddle up all of the services. Since the AWS UI and docs are themselves oriented around services, most users should be familiar with the service brands and understand which resources belong to which service. Thus this categorization follows the primary categorization used within the AWS Console, preferring EC2-VPC over EC2-Classic-style bucketing. --- website/source/layouts/aws.erb | 636 +++++++++++++++++++-------------- 1 file changed, 373 insertions(+), 263 deletions(-) diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index cf1034231..a212bb697 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -1,296 +1,406 @@ <% wrap_layout :inner do %> - <% content_for :sidebar do %> - + <% end %> + + <%= yield %> <% end %> From 8ce3d49895095bbb505d61ead7f79985a04172e3 Mon Sep 17 00:00:00 2001 From: Clint Date: Thu, 23 Jul 2015 11:27:17 -0500 Subject: [PATCH 41/48] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 159240163..8cec80916 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ IMPROVEMENTS: * provider/aws: Validate credentials before walking the graph [GH-2730] - * provider/aws: Add website_domain for S3 buckets [GH-2210] + * provider/aws: Added website_domain for S3 buckets [GH-2210] * provider/aws: ELB names are now optional, and generated by Terraform if omitted [GH-2571] + * provider/aws: Added `source_dest_check` attribute to the aws_network_interface [GH-2741] BUG FIXES: From 38ce950b4cda0bf538a2b9b4848f93d5e312bad3 Mon Sep 17 00:00:00 2001 From: Clint Date: Fri, 24 Jul 2015 12:01:06 -0500 Subject: [PATCH 42/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cec80916..6b0351cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ IMPROVEMENTS: * provider/aws: Added website_domain for S3 buckets [GH-2210] * provider/aws: ELB names are now optional, and generated by Terraform if omitted [GH-2571] * provider/aws: Added `source_dest_check` attribute to the aws_network_interface [GH-2741] + * provider/aws: Clean up externally removed Launch Configurations [GH-2806] BUG FIXES: From dfe0efaf175653b7ea34a6776a9b882e055f060b Mon Sep 17 00:00:00 2001 From: Christopher Tiwald Date: Thu, 16 Jul 2015 01:37:21 -0400 Subject: [PATCH 43/48] aws_db_instance: Only write lowercase engines to the state file. Amazon accepts mixed-case engines, but only returns lowercase. Without the proper StateFunc, every apply of a mixed-case engine will result in a new db instance. Standardize on lowercase. --- builtin/providers/aws/resource_aws_db_instance.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builtin/providers/aws/resource_aws_db_instance.go b/builtin/providers/aws/resource_aws_db_instance.go index 47a98b73d..6ca1916b5 100644 --- a/builtin/providers/aws/resource_aws_db_instance.go +++ b/builtin/providers/aws/resource_aws_db_instance.go @@ -46,6 +46,10 @@ func resourceAwsDbInstance() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + StateFunc: func(v interface{}) string { + value := v.(string) + return strings.ToLower(value) + }, }, "engine_version": &schema.Schema{ From 4f085ba550fcebaf5c57ca6cf1deab27351eea70 Mon Sep 17 00:00:00 2001 From: Christopher Tiwald Date: Thu, 16 Jul 2015 01:39:23 -0400 Subject: [PATCH 44/48] aws_db_instance: Add mixed-case engine test to ensure StateFunc works. --- builtin/providers/aws/resource_aws_db_instance_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_db_instance_test.go b/builtin/providers/aws/resource_aws_db_instance_test.go index ef1931b03..b60a01da9 100644 --- a/builtin/providers/aws/resource_aws_db_instance_test.go +++ b/builtin/providers/aws/resource_aws_db_instance_test.go @@ -176,7 +176,7 @@ resource "aws_db_instance" "bar" { identifier = "foobarbaz-test-terraform-%d" allocated_storage = 10 - engine = "mysql" + engine = "MySQL" engine_version = "5.6.21" instance_class = "db.t1.micro" name = "baz" From 6c86ae3a191c92c37c8330ec121dda0072e0bfe8 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Mon, 27 Jul 2015 16:14:01 +0100 Subject: [PATCH 45/48] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b0351cf1..9ea5104ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ IMPROVEMENTS: + * core: Add resource IDs to errors coming from `apply`/`refresh` [GH-2815] * provider/aws: Validate credentials before walking the graph [GH-2730] * provider/aws: Added website_domain for S3 buckets [GH-2210] * provider/aws: ELB names are now optional, and generated by Terraform if omitted [GH-2571] @@ -10,6 +11,7 @@ IMPROVEMENTS: BUG FIXES: + * core: Prevent error duplication in `apply` [GH-2815] * provider/aws: Fix issue with toggling monitoring in AWS Instances [GH-2794] * provider/aws: Fix issue with Spot Instance Requests and cancellation [GH-2805] From 99f9b93b575e33273241ff08e58c589ba07819ba Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 7 Jul 2015 15:12:41 -0600 Subject: [PATCH 46/48] provider/aws: Error when unable to find a Root Block Device name Fixes #2633 --- builtin/providers/aws/resource_aws_instance.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index 6d6657c15..d6ec35af1 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -778,6 +778,10 @@ func fetchRootDeviceName(ami string, conn *ec2.EC2) (*string, error) { rootDeviceName = image.BlockDeviceMappings[0].DeviceName } + if rootDeviceName == nil { + return nil, fmt.Errorf("[WARN] Error finding Root Device Name for AMI (%s)", ami) + } + return rootDeviceName, nil } From 2b082166866305cf4ae72a8baa564076933435ac Mon Sep 17 00:00:00 2001 From: Clint Date: Mon, 27 Jul 2015 12:22:23 -0500 Subject: [PATCH 47/48] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ea5104ef..952ab4b07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ BUG FIXES: * core: Prevent error duplication in `apply` [GH-2815] * provider/aws: Fix issue with toggling monitoring in AWS Instances [GH-2794] * provider/aws: Fix issue with Spot Instance Requests and cancellation [GH-2805] + * provider/aws: Fixx issue when unable to find a Root Block Device name of an Instance Backed + AMI [GH-2646] ## 0.6.1 (July 20, 2015) From 5c7d22efcdc54f7982e13a76ada5b91bd9529fb4 Mon Sep 17 00:00:00 2001 From: Clint Date: Mon, 27 Jul 2015 14:28:47 -0500 Subject: [PATCH 48/48] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 952ab4b07..a548f290e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ IMPROVEMENTS: * provider/aws: Validate credentials before walking the graph [GH-2730] * provider/aws: Added website_domain for S3 buckets [GH-2210] * provider/aws: ELB names are now optional, and generated by Terraform if omitted [GH-2571] + * provider/aws: Downcase RDS engine names to prevent continuous diffs [GH-2745] * provider/aws: Added `source_dest_check` attribute to the aws_network_interface [GH-2741] * provider/aws: Clean up externally removed Launch Configurations [GH-2806]