diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 858d477e4..c740e4bc8 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -221,6 +221,7 @@ func Provider() terraform.ResourceProvider { "aws_opsworks_mysql_layer": resourceAwsOpsworksMysqlLayer(), "aws_opsworks_ganglia_layer": resourceAwsOpsworksGangliaLayer(), "aws_opsworks_custom_layer": resourceAwsOpsworksCustomLayer(), + "aws_placement_group": resourceAwsPlacementGroup(), "aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(), "aws_rds_cluster": resourceAwsRDSCluster(), "aws_rds_cluster_instance": resourceAwsRDSClusterInstance(), diff --git a/builtin/providers/aws/resource_aws_placement_group.go b/builtin/providers/aws/resource_aws_placement_group.go new file mode 100644 index 000000000..9f0452f75 --- /dev/null +++ b/builtin/providers/aws/resource_aws_placement_group.go @@ -0,0 +1,150 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsPlacementGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsPlacementGroupCreate, + Read: resourceAwsPlacementGroupRead, + Delete: resourceAwsPlacementGroupDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "strategy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceAwsPlacementGroupCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + name := d.Get("name").(string) + input := ec2.CreatePlacementGroupInput{ + GroupName: aws.String(name), + Strategy: aws.String(d.Get("strategy").(string)), + } + log.Printf("[DEBUG] Creating EC2 Placement group: %s", input) + _, err := conn.CreatePlacementGroup(&input) + if err != nil { + return err + } + + wait := resource.StateChangeConf{ + Pending: []string{"pending"}, + Target: "available", + Timeout: 5 * time.Minute, + MinTimeout: 1 * time.Second, + Refresh: func() (interface{}, string, error) { + out, err := conn.DescribePlacementGroups(&ec2.DescribePlacementGroupsInput{ + GroupNames: []*string{aws.String(name)}, + }) + + if err != nil { + return out, "", err + } + + if len(out.PlacementGroups) == 0 { + return out, "", fmt.Errorf("Placement group not found (%q)", name) + } + pg := out.PlacementGroups[0] + + return out, *pg.State, nil + }, + } + + _, err = wait.WaitForState() + if err != nil { + return err + } + + log.Printf("[DEBUG] EC2 Placement group created: %q", name) + + d.SetId(name) + + return resourceAwsPlacementGroupRead(d, meta) +} + +func resourceAwsPlacementGroupRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + input := ec2.DescribePlacementGroupsInput{ + GroupNames: []*string{aws.String(d.Get("name").(string))}, + } + out, err := conn.DescribePlacementGroups(&input) + if err != nil { + return err + } + pg := out.PlacementGroups[0] + + log.Printf("[DEBUG] Received EC2 Placement Group: %s", pg) + + d.Set("name", pg.GroupName) + d.Set("strategy", pg.Strategy) + + return nil +} + +func resourceAwsPlacementGroupDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + log.Printf("[DEBUG] Deleting EC2 Placement Group %q", d.Id()) + _, err := conn.DeletePlacementGroup(&ec2.DeletePlacementGroupInput{ + GroupName: aws.String(d.Id()), + }) + if err != nil { + return err + } + + wait := resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: "deleted", + Timeout: 5 * time.Minute, + MinTimeout: 1 * time.Second, + Refresh: func() (interface{}, string, error) { + out, err := conn.DescribePlacementGroups(&ec2.DescribePlacementGroupsInput{ + GroupNames: []*string{aws.String(d.Id())}, + }) + + if err != nil { + awsErr := err.(awserr.Error) + if awsErr.Code() == "InvalidPlacementGroup.Unknown" { + return out, "deleted", nil + } + return out, "", awsErr + } + + if len(out.PlacementGroups) == 0 { + return out, "deleted", nil + } + + pg := out.PlacementGroups[0] + + return out, *pg.State, nil + }, + } + + _, err = wait.WaitForState() + if err != nil { + return err + } + + d.SetId("") + return nil +} diff --git a/builtin/providers/aws/resource_aws_placement_group_test.go b/builtin/providers/aws/resource_aws_placement_group_test.go new file mode 100644 index 000000000..a68e43e92 --- /dev/null +++ b/builtin/providers/aws/resource_aws_placement_group_test.go @@ -0,0 +1,98 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" +) + +func TestAccAWSPlacementGroup_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSPlacementGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSPlacementGroupConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSPlacementGroupExists("aws_placement_group.pg"), + ), + }, + }, + }) +} + +func testAccCheckAWSPlacementGroupDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_placement_group" { + continue + } + _, err := conn.DeletePlacementGroup(&ec2.DeletePlacementGroupInput{ + GroupName: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } + } + return nil +} + +func testAccCheckAWSPlacementGroupExists(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 Placement Group ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).ec2conn + _, err := conn.DescribePlacementGroups(&ec2.DescribePlacementGroupsInput{ + GroupNames: []*string{aws.String(rs.Primary.ID)}, + }) + + if err != nil { + return fmt.Errorf("Placement Group error: %v", err) + } + return nil + } +} + +func testAccCheckAWSDestroyPlacementGroup(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 Placement Group ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).ec2conn + _, err := conn.DeletePlacementGroup(&ec2.DeletePlacementGroupInput{ + GroupName: aws.String(rs.Primary.ID), + }) + + if err != nil { + return fmt.Errorf("Error destroying Placement Group (%s): %s", rs.Primary.ID, err) + } + return nil + } +} + +var testAccAWSPlacementGroupConfig = ` +resource "aws_placement_group" "pg" { + name = "tf-test-pg" + strategy = "cluster" +} +` diff --git a/website/source/docs/providers/aws/r/placement_group.html.markdown b/website/source/docs/providers/aws/r/placement_group.html.markdown new file mode 100644 index 000000000..e4ad98df8 --- /dev/null +++ b/website/source/docs/providers/aws/r/placement_group.html.markdown @@ -0,0 +1,34 @@ +--- +layout: "aws" +page_title: "AWS: aws_placement_group" +sidebar_current: "docs-aws-resource-placement-group" +description: |- + Provides an EC2 placement group. +--- + +# aws\_placement\_group + +Provides an EC2 placement group. Read more about placement groups +in [AWS Docs](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html). + +## Example Usage + +``` +resource "aws_placement_group" "web" { + name = "hunky-dory-pg" + strategy = "cluster" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the placement group. +* `strategy` - (Required) The placement strategy. The only supported value is `cluster` + +## Attributes Reference + +The following attributes are exported: + +* `id` - The name of the placement group. diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 1a1ea529f..c26f0cb4d 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -49,7 +49,7 @@ - > + > EC2 Resources