From 9dd4e5bcb033071caf9378c875e7aaaaa1be100c Mon Sep 17 00:00:00 2001 From: Paul Stack Date: Tue, 9 May 2017 17:48:57 +0300 Subject: [PATCH] provider/aws: Add support for targets to aws_ssm_association (#14246) * provider/aws: Add support for targets to aws_ssm_association Fixes: #13975 ``` % make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSSSMAssociation_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/05/05 20:32:43 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSSSMAssociation_ -timeout 120m === RUN TestAccAWSSSMAssociation_basic --- PASS: TestAccAWSSSMAssociation_basic (139.13s) === RUN TestAccAWSSSMAssociation_withTargets --- PASS: TestAccAWSSSMAssociation_withTargets (33.19s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 172.343s ``` * Update ssm_association.html.markdown --- .../aws/resource_aws_ssm_association.go | 53 +++++++++++--- .../aws/resource_aws_ssm_association_test.go | 72 ++++++++++++++++--- ...ource_aws_ssm_maintenance_window_target.go | 40 +---------- ...esource_aws_ssm_maintenance_window_task.go | 4 +- builtin/providers/aws/structure.go | 37 ++++++++++ .../aws/r/ssm_association.html.markdown | 5 +- 6 files changed, 150 insertions(+), 61 deletions(-) diff --git a/builtin/providers/aws/resource_aws_ssm_association.go b/builtin/providers/aws/resource_aws_ssm_association.go index 30bc19ca3..be83ce767 100644 --- a/builtin/providers/aws/resource_aws_ssm_association.go +++ b/builtin/providers/aws/resource_aws_ssm_association.go @@ -17,22 +17,46 @@ func resourceAwsSsmAssociation() *schema.Resource { Delete: resourceAwsSsmAssociationDelete, Schema: map[string]*schema.Schema{ + "association_id": { + Type: schema.TypeString, + Computed: true, + }, "instance_id": { Type: schema.TypeString, ForceNew: true, - Required: true, + Optional: true, }, "name": { Type: schema.TypeString, ForceNew: true, Required: true, }, - "parameters": &schema.Schema{ + "parameters": { Type: schema.TypeMap, Optional: true, ForceNew: true, Computed: true, }, + "targets": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "values": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, }, } } @@ -43,14 +67,21 @@ func resourceAwsSsmAssociationCreate(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] SSM association create: %s", d.Id()) assosciationInput := &ssm.CreateAssociationInput{ - Name: aws.String(d.Get("name").(string)), - InstanceId: aws.String(d.Get("instance_id").(string)), + Name: aws.String(d.Get("name").(string)), + } + + if v, ok := d.GetOk("instance_id"); ok { + assosciationInput.InstanceId = aws.String(v.(string)) } if v, ok := d.GetOk("parameters"); ok { assosciationInput.Parameters = expandSSMDocumentParameters(v.(map[string]interface{})) } + if _, ok := d.GetOk("targets"); ok { + assosciationInput.Targets = expandAwsSsmTargets(d) + } + resp, err := ssmconn.CreateAssociation(assosciationInput) if err != nil { return errwrap.Wrapf("[ERROR] Error creating SSM association: {{err}}", err) @@ -61,6 +92,7 @@ func resourceAwsSsmAssociationCreate(d *schema.ResourceData, meta interface{}) e } d.SetId(*resp.AssociationDescription.Name) + d.Set("association_id", resp.AssociationDescription.AssociationId) return resourceAwsSsmAssociationRead(d, meta) } @@ -68,11 +100,10 @@ func resourceAwsSsmAssociationCreate(d *schema.ResourceData, meta interface{}) e func resourceAwsSsmAssociationRead(d *schema.ResourceData, meta interface{}) error { ssmconn := meta.(*AWSClient).ssmconn - log.Printf("[DEBUG] Reading SSM Assosciation: %s", d.Id()) + log.Printf("[DEBUG] Reading SSM Association: %s", d.Id()) params := &ssm.DescribeAssociationInput{ - Name: aws.String(d.Get("name").(string)), - InstanceId: aws.String(d.Get("instance_id").(string)), + AssociationId: aws.String(d.Get("association_id").(string)), } resp, err := ssmconn.DescribeAssociation(params) @@ -88,6 +119,11 @@ func resourceAwsSsmAssociationRead(d *schema.ResourceData, meta interface{}) err d.Set("instance_id", association.InstanceId) d.Set("name", association.Name) d.Set("parameters", association.Parameters) + d.Set("association_id", association.AssociationId) + + if err := d.Set("targets", flattenAwsSsmTargets(association.Targets)); err != nil { + return fmt.Errorf("[DEBUG] Error setting targets error: %#v", err) + } return nil } @@ -98,8 +134,7 @@ func resourceAwsSsmAssociationDelete(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Deleting SSM Assosciation: %s", d.Id()) params := &ssm.DeleteAssociationInput{ - Name: aws.String(d.Get("name").(string)), - InstanceId: aws.String(d.Get("instance_id").(string)), + AssociationId: aws.String(d.Get("association_id").(string)), } _, err := ssmconn.DeleteAssociation(params) diff --git a/builtin/providers/aws/resource_aws_ssm_association_test.go b/builtin/providers/aws/resource_aws_ssm_association_test.go index 6a705164d..0dfc752db 100644 --- a/builtin/providers/aws/resource_aws_ssm_association_test.go +++ b/builtin/providers/aws/resource_aws_ssm_association_test.go @@ -19,7 +19,7 @@ func TestAccAWSSSMAssociation_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSSSMAssociationDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSSSMAssociationBasicConfig(name), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSSMAssociationExists("aws_ssm_association.foo"), @@ -29,6 +29,23 @@ func TestAccAWSSSMAssociation_basic(t *testing.T) { }) } +func TestAccAWSSSMAssociation_withTargets(t *testing.T) { + name := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSSMAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSSMAssociationBasicConfigWithTargets(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSSMAssociationExists("aws_ssm_association.foo"), + ), + }, + }, + }) +} + func testAccCheckAWSSSMAssociationExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -43,12 +60,14 @@ func testAccCheckAWSSSMAssociationExists(n string) resource.TestCheckFunc { conn := testAccProvider.Meta().(*AWSClient).ssmconn _, err := conn.DescribeAssociation(&ssm.DescribeAssociationInput{ - Name: aws.String(rs.Primary.Attributes["name"]), - InstanceId: aws.String(rs.Primary.Attributes["instance_id"]), + AssociationId: aws.String(rs.Primary.Attributes["association_id"]), }) if err != nil { - return fmt.Errorf("Could not descripbe the assosciation - %s", err) + if wserr, ok := err.(awserr.Error); ok && wserr.Code() == "AssociationDoesNotExist" { + return nil + } + return err } return nil @@ -64,24 +83,57 @@ func testAccCheckAWSSSMAssociationDestroy(s *terraform.State) error { } out, err := conn.DescribeAssociation(&ssm.DescribeAssociationInput{ - Name: aws.String(rs.Primary.Attributes["name"]), - InstanceId: aws.String(rs.Primary.Attributes["instance_id"]), + AssociationId: aws.String(rs.Primary.Attributes["association_id"]), }) if err != nil { - // InvalidDocument means it's gone, this is good - if wserr, ok := err.(awserr.Error); ok && wserr.Code() == "InvalidDocument" { + if wserr, ok := err.(awserr.Error); ok && wserr.Code() == "AssociationDoesNotExist" { return nil } return err } if out != nil { - return fmt.Errorf("Expected AWS SSM Assosciation to be gone, but was still found") + return fmt.Errorf("Expected AWS SSM Association to be gone, but was still found") } } - return fmt.Errorf("Default error in SSM Assosciation Test") + return fmt.Errorf("Default error in SSM Association Test") +} + +func testAccAWSSSMAssociationBasicConfigWithTargets(rName string) string { + return fmt.Sprintf(` +resource "aws_ssm_document" "foo_document" { + name = "test_document_association-%s", + document_type = "Command" + content = <