From d94f07f6bb8fdb620fef1e362327eff789ea5c04 Mon Sep 17 00:00:00 2001 From: liamjbennett Date: Fri, 2 Sep 2016 08:43:03 +0100 Subject: [PATCH 1/2] provider/aws: add aws_ssm_association resource --- builtin/providers/aws/provider.go | 1 + .../aws/resource_aws_ssm_association.go | 127 ++++++++++++++++ .../aws/resource_aws_ssm_association_test.go | 136 ++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_ssm_association.go create mode 100644 builtin/providers/aws/resource_aws_ssm_association_test.go diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 29db928eb90c..b6d9e44b8554 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -312,6 +312,7 @@ func Provider() terraform.ResourceProvider { "aws_security_group": resourceAwsSecurityGroup(), "aws_security_group_rule": resourceAwsSecurityGroupRule(), "aws_simpledb_domain": resourceAwsSimpleDBDomain(), + "aws_ssm_association": resourceAwsSsmAssociation(), "aws_ssm_document": resourceAwsSsmDocument(), "aws_spot_instance_request": resourceAwsSpotInstanceRequest(), "aws_spot_fleet_request": resourceAwsSpotFleetRequest(), diff --git a/builtin/providers/aws/resource_aws_ssm_association.go b/builtin/providers/aws/resource_aws_ssm_association.go new file mode 100644 index 000000000000..afcac8453968 --- /dev/null +++ b/builtin/providers/aws/resource_aws_ssm_association.go @@ -0,0 +1,127 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsSsmAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSsmAssociationCreate, + Read: resourceAwsSsmAssociationRead, + Delete: resourceAwsSsmAssociationDelete, + + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "name": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "parameters": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Computed: true, + }, + }, + } +} + +func resourceAwsSsmAssociationCreate(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + 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)), + } + + if v, ok := d.GetOk("parameters"); ok { + assosciationInput.Parameters = expandDocumentParameters(v.(map[string]interface{})) + } + + resp, err := ssmconn.CreateAssociation(assosciationInput) + + if err != nil { + return errwrap.Wrapf("[ERROR] Error creating SSM association: {{err}}", err) + } + + if resp.AssociationDescription != nil { + d.SetId(*resp.AssociationDescription.Name) + } else { + return fmt.Errorf("[ERROR] AssociationDescription was nil") + } + + return resourceAwsSsmAssociationRead(d, meta) +} + +func resourceAwsSsmAssociationRead(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] Reading SSM Assosciation: %s", d.Id()) + + params := &ssm.DescribeAssociationInput{ + Name: aws.String(d.Get("name").(string)), + InstanceId: aws.String(d.Get("instance_id").(string)), + } + + resp, err := ssmconn.DescribeAssociation(params) + + if err != nil { + return errwrap.Wrapf("[ERROR] Error reading SSM association: {{err}}", err) + } + + if resp.AssociationDescription != nil { + association := resp.AssociationDescription + + d.Set("instance_id", association.InstanceId) + d.Set("name", association.Name) + d.Set("parameters", association.Parameters) + + } else { + return fmt.Errorf("[ERROR] AssociationDescription was nil") + } + + return nil +} + +func resourceAwsSsmAssociationDelete(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + 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)), + } + + _, err := ssmconn.DeleteAssociation(params) + + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting SSM association: {{err}}", err) + } + + return nil +} + +func expandDocumentParameters(params map[string]interface{}) map[string][]*string { + var docParams = make(map[string][]*string) + for k, v := range params { + var values []*string + values[0] = aws.String(v.(string)) + docParams[k] = values + } + + return docParams +} diff --git a/builtin/providers/aws/resource_aws_ssm_association_test.go b/builtin/providers/aws/resource_aws_ssm_association_test.go new file mode 100644 index 000000000000..3a8e1ec89567 --- /dev/null +++ b/builtin/providers/aws/resource_aws_ssm_association_test.go @@ -0,0 +1,136 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSSSMAssociation_basic(t *testing.T) { + name := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSSMAssociationDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSSSMAssociationBasicConfig(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] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No SSM Assosciation ID is set") + } + + 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"]), + }) + + if err != nil { + return fmt.Errorf("Could not descripbe the assosciation - %s", err) + } + + return nil + } +} + +func testAccCheckAWSSSMAssociationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ssmconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ssm_association" { + continue + } + + out, err := conn.DescribeAssociation(&ssm.DescribeAssociationInput{ + Name: aws.String(rs.Primary.Attributes["name"]), + InstanceId: aws.String(rs.Primary.Attributes["instance_id"]), + }) + + if err != nil { + // InvalidDocument means it's gone, this is good + if wserr, ok := err.(awserr.Error); ok && wserr.Code() == "InvalidDocument" { + return nil + } + return err + } + + if out != nil { + return fmt.Errorf("Expected AWS SSM Assosciation to be gone, but was still found") + } + } + + return fmt.Errorf("Default error in SSM Assosciation Test") +} + +func testAccAWSSSMAssociationBasicConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_security_group" "tf_test_foo" { + name = "tf_test_foo-%s" + description = "foo" + ingress { + protocol = "icmp" + from_port = -1 + to_port = -1 + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "foo" { + # eu-west-1 + ami = "ami-f77ac884" + availability_zone = "eu-west-1a" + instance_type = "t2.small" + security_groups = ["${aws_security_group.tf_test_foo.name}"] +} + +resource "aws_ssm_document" "foo_document" { + name = "test_document_association-%s", + content = < Date: Fri, 2 Sep 2016 08:43:14 +0100 Subject: [PATCH 2/2] Adding documentation for resource `aws_ssm_association` --- .../aws/r/ssm_association.html.markdown | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 website/source/docs/providers/aws/r/ssm_association.html.markdown diff --git a/website/source/docs/providers/aws/r/ssm_association.html.markdown b/website/source/docs/providers/aws/r/ssm_association.html.markdown new file mode 100644 index 000000000000..261b6108af42 --- /dev/null +++ b/website/source/docs/providers/aws/r/ssm_association.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "aws" +page_title: "AWS: aws_ssm_association" +sidebar_current: "docs-aws-resource-ssm-association" +description: |- + Assosciates an SSM Document to an instance. +--- + +# aws\_ssm\_association + +Assosciates an SSM Document to an instance. + +## Example Usage + +``` +resource "aws_security_group" "tf_test_foo" { + name = "tf_test_foo" + description = "foo" + ingress { + protocol = "icmp" + from_port = -1 + to_port = -1 + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_instance" "foo" { + # eu-west-1 + ami = "ami-f77ac884" + availability_zone = "eu-west-1a" + instance_type = "t2.small" + security_groups = ["${aws_security_group.tf_test_foo.name}"] +} + +resource "aws_ssm_document" "foo_document" { + name = "test_document_association-%s", + content = <