From 8fee7642a9d6e314b8c3ffc1f86e5974b2ee6d00 Mon Sep 17 00:00:00 2001 From: Liam Bennett Date: Fri, 28 Oct 2016 10:59:12 +0100 Subject: [PATCH] New AWS resource `ssm_activation` (#9111) Adding a new resource to support activation of managed instances for on-premise virtual-machines. --- builtin/providers/aws/provider.go | 1 + .../aws/resource_aws_ssm_activation.go | 168 ++++++++++++++++++ .../aws/resource_aws_ssm_activation_test.go | 131 ++++++++++++++ .../aws/r/ssm_activation.html.markdown | 65 +++++++ 4 files changed, 365 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_ssm_activation.go create mode 100644 builtin/providers/aws/resource_aws_ssm_activation_test.go create mode 100644 website/source/docs/providers/aws/r/ssm_activation.html.markdown diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index b7388453c..ed6c78ce0 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -332,6 +332,7 @@ func Provider() terraform.ResourceProvider { "aws_security_group": resourceAwsSecurityGroup(), "aws_security_group_rule": resourceAwsSecurityGroupRule(), "aws_simpledb_domain": resourceAwsSimpleDBDomain(), + "aws_ssm_activation": resourceAwsSsmActivation(), "aws_ssm_association": resourceAwsSsmAssociation(), "aws_ssm_document": resourceAwsSsmDocument(), "aws_spot_datafeed_subscription": resourceAwsSpotDataFeedSubscription(), diff --git a/builtin/providers/aws/resource_aws_ssm_activation.go b/builtin/providers/aws/resource_aws_ssm_activation.go new file mode 100644 index 000000000..9cceda4ae --- /dev/null +++ b/builtin/providers/aws/resource_aws_ssm_activation.go @@ -0,0 +1,168 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsSsmActivation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSsmActivationCreate, + Read: resourceAwsSsmActivationRead, + Delete: resourceAwsSsmActivationDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "expired": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "expiration_date": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "iam_role": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "registration_limit": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + "registration_count": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + }, + } +} + +func resourceAwsSsmActivationCreate(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] SSM activation create: %s", d.Id()) + + activationInput := &ssm.CreateActivationInput{ + IamRole: aws.String(d.Get("name").(string)), + } + + if _, ok := d.GetOk("name"); ok { + activationInput.DefaultInstanceName = aws.String(d.Get("name").(string)) + } + + if _, ok := d.GetOk("description"); ok { + activationInput.Description = aws.String(d.Get("description").(string)) + } + + if _, ok := d.GetOk("expiration_date"); ok { + activationInput.ExpirationDate = aws.Time(d.Get("expiration_date").(time.Time)) + } + + if _, ok := d.GetOk("iam_role"); ok { + activationInput.IamRole = aws.String(d.Get("iam_role").(string)) + } + + if _, ok := d.GetOk("registration_limit"); ok { + activationInput.RegistrationLimit = aws.Int64(int64(d.Get("registration_limit").(int))) + } + + // Retry to allow iam_role to be created and policy attachment to take place + var resp *ssm.CreateActivationOutput + err := resource.Retry(30*time.Second, func() *resource.RetryError { + var err error + + resp, err = ssmconn.CreateActivation(activationInput) + + if err != nil { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + }) + + if err != nil { + return errwrap.Wrapf("[ERROR] Error creating SSM activation: {{err}}", err) + } + + if resp.ActivationId == nil { + return fmt.Errorf("[ERROR] ActivationId was nil") + } + d.SetId(*resp.ActivationId) + + return resourceAwsSsmActivationRead(d, meta) +} + +func resourceAwsSsmActivationRead(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] Reading SSM Activation: %s", d.Id()) + + params := &ssm.DescribeActivationsInput{ + Filters: []*ssm.DescribeActivationsFilter{ + { + FilterKey: aws.String("ActivationIds"), + FilterValues: []*string{ + aws.String(d.Id()), + }, + }, + }, + MaxResults: aws.Int64(1), + } + + resp, err := ssmconn.DescribeActivations(params) + + if err != nil { + return errwrap.Wrapf("[ERROR] Error reading SSM activation: {{err}}", err) + } + if resp.ActivationList == nil || len(resp.ActivationList) == 0 { + return fmt.Errorf("[ERROR] ActivationList was nil or empty") + } + + activation := resp.ActivationList[0] // Only 1 result as MaxResults is 1 above + d.Set("name", activation.DefaultInstanceName) + d.Set("description", activation.Description) + d.Set("expiration_date", activation.ExpirationDate) + d.Set("expired", activation.Expired) + d.Set("iam_role", activation.IamRole) + d.Set("registration_limit", activation.RegistrationLimit) + d.Set("registration_count", activation.RegistrationsCount) + + return nil +} + +func resourceAwsSsmActivationDelete(d *schema.ResourceData, meta interface{}) error { + ssmconn := meta.(*AWSClient).ssmconn + + log.Printf("[DEBUG] Deleting SSM Activation: %s", d.Id()) + + params := &ssm.DeleteActivationInput{ + ActivationId: aws.String(d.Id()), + } + + _, err := ssmconn.DeleteActivation(params) + + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting SSM activation: {{err}}", err) + } + + return nil +} diff --git a/builtin/providers/aws/resource_aws_ssm_activation_test.go b/builtin/providers/aws/resource_aws_ssm_activation_test.go new file mode 100644 index 000000000..bfedcf954 --- /dev/null +++ b/builtin/providers/aws/resource_aws_ssm_activation_test.go @@ -0,0 +1,131 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "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 TestAccAWSSSMActivation_basic(t *testing.T) { + name := acctest.RandString(10) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSSMActivationDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSSSMActivationBasicConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSSMActivationExists("aws_ssm_activation.foo"), + ), + }, + }, + }) +} + +func testAccCheckAWSSSMActivationExists(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 Activation ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).ssmconn + + _, err := conn.DescribeActivations(&ssm.DescribeActivationsInput{ + Filters: []*ssm.DescribeActivationsFilter{ + { + FilterKey: aws.String("ActivationIds"), + FilterValues: []*string{ + aws.String(rs.Primary.ID), + }, + }, + }, + MaxResults: aws.Int64(1), + }) + + if err != nil { + return fmt.Errorf("Could not descripbe the activation - %s", err) + } + + return nil + } +} + +func testAccCheckAWSSSMActivationDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ssmconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ssm_activation" { + continue + } + + out, err := conn.DescribeActivations(&ssm.DescribeActivationsInput{ + Filters: []*ssm.DescribeActivationsFilter{ + { + FilterKey: aws.String("ActivationIds"), + FilterValues: []*string{ + aws.String(rs.Primary.ID), + }, + }, + }, + MaxResults: aws.Int64(1), + }) + + if err != nil { + return err + } + + if len(out.ActivationList) > 0 { + return fmt.Errorf("Expected AWS SSM Activation to be gone, but was still found") + } + + return nil + } + + return fmt.Errorf("Default error in SSM Activation Test") +} + +func testAccAWSSSMActivationBasicConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test_role" { + name = "test_role-%s" + assume_role_policy = <