Skip to content

Commit

Permalink
Merge pull request #15360 from sean-/gh-7754
Browse files Browse the repository at this point in the history
resource/aws_placement_group: add support for the attribute partition count
  • Loading branch information
ewbankkit authored Oct 13, 2021
2 parents 1cf42ed + a2ce9b2 commit a4b2dea
Show file tree
Hide file tree
Showing 14 changed files with 335 additions and 137 deletions.
3 changes: 3 additions & 0 deletions .changelog/15360.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_placement_group: Add `partition_count` argument
```
7 changes: 7 additions & 0 deletions .changelog/7777.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_instance: Add `placement_partition_number` argument
```

```release-note:enhancement
data-source/aws_instance: Add `placement_partition_number` attribute
```
7 changes: 7 additions & 0 deletions aws/data_source_aws_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func dataSourceAwsInstance() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"placement_partition_number": {
Type: schema.TypeInt,
Computed: true,
},
"tenancy": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -450,6 +454,9 @@ func instanceDescriptionAttributes(d *schema.ResourceData, instance *ec2.Instanc
if instance.Placement.GroupName != nil {
d.Set("placement_group", instance.Placement.GroupName)
}
if instance.Placement.PartitionNumber != nil {
d.Set("placement_partition_number", instance.Placement.PartitionNumber)
}
if instance.Placement.Tenancy != nil {
d.Set("tenancy", instance.Placement.Tenancy)
}
Expand Down
4 changes: 4 additions & 0 deletions aws/internal/service/ec2/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ const (
ErrCodeInvalidPermissionNotFound = "InvalidPermission.NotFound"
)

const (
ErrCodeInvalidPlacementGroupUnknown = "InvalidPlacementGroup.Unknown"
)

// See https://docs.aws.amazon.com/vm-import/latest/userguide/vmimport-image-import.html#check-import-task-status
const (
EbsSnapshotImportActive = "active"
Expand Down
38 changes: 38 additions & 0 deletions aws/internal/service/ec2/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -973,3 +973,41 @@ func ManagedPrefixListEntryByIDAndCIDR(conn *ec2.EC2, id, cidr string) (*ec2.Pre

return nil, &resource.NotFoundError{}
}

func PlacementGroupByName(conn *ec2.EC2, name string) (*ec2.PlacementGroup, error) {
input := &ec2.DescribePlacementGroupsInput{
GroupNames: aws.StringSlice([]string{name}),
}

output, err := conn.DescribePlacementGroups(input)

if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidPlacementGroupUnknown) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || len(output.PlacementGroups) == 0 || output.PlacementGroups[0] == nil {
return nil, tfresource.NewEmptyResultError(input)
}

if count := len(output.PlacementGroups); count > 1 {
return nil, tfresource.NewTooManyResultsError(count, input)
}

placementGroup := output.PlacementGroups[0]

if state := aws.StringValue(placementGroup.State); state == ec2.PlacementGroupStateDeleted {
return nil, &resource.NotFoundError{
Message: state,
LastRequest: input,
}
}

return placementGroup, nil
}
16 changes: 16 additions & 0 deletions aws/internal/service/ec2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,22 @@ func ManagedPrefixListState(conn *ec2.EC2, id string) resource.StateRefreshFunc
}
}

func PlacementGroupState(conn *ec2.EC2, name string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := finder.PlacementGroupByName(conn, name)

if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return output, aws.StringValue(output.State), nil
}
}

func VpcEndpointState(conn *ec2.EC2, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := finder.VpcEndpointByID(conn, id)
Expand Down
39 changes: 39 additions & 0 deletions aws/internal/service/ec2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,45 @@ func ManagedPrefixListDeleted(conn *ec2.EC2, id string) (*ec2.ManagedPrefixList,
return nil, err
}

const (
PlacementGroupCreatedTimeout = 5 * time.Minute
PlacementGroupDeletedTimeout = 5 * time.Minute
)

func PlacementGroupCreated(conn *ec2.EC2, name string) (*ec2.PlacementGroup, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.PlacementGroupStatePending},
Target: []string{ec2.PlacementGroupStateAvailable},
Timeout: PlacementGroupCreatedTimeout,
Refresh: PlacementGroupState(conn, name),
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.PlacementGroup); ok {
return output, err
}

return nil, err
}

func PlacementGroupDeleted(conn *ec2.EC2, name string) (*ec2.PlacementGroup, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.PlacementGroupStateDeleting},
Target: []string{},
Timeout: PlacementGroupDeletedTimeout,
Refresh: PlacementGroupState(conn, name),
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.PlacementGroup); ok {
return output, err
}

return nil, err
}

func VpcEndpointAccepted(conn *ec2.EC2, vpcEndpointID string, timeout time.Duration) (*ec2.VpcEndpoint, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{tfec2.VpcEndpointStatePendingAcceptance},
Expand Down
13 changes: 13 additions & 0 deletions aws/resource_aws_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,12 @@ func resourceAwsInstance() *schema.Resource {
Computed: true,
ForceNew: true,
},
"placement_partition_number": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
},
"primary_network_interface_id": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -923,6 +929,9 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
if instance.Placement.GroupName != nil {
d.Set("placement_group", instance.Placement.GroupName)
}
if instance.Placement.PartitionNumber != nil {
d.Set("placement_partition_number", instance.Placement.PartitionNumber)
}
if instance.Placement.Tenancy != nil {
d.Set("tenancy", instance.Placement.Tenancy)
}
Expand Down Expand Up @@ -2638,6 +2647,10 @@ func buildAwsInstanceOpts(d *schema.ResourceData, meta interface{}) (*awsInstanc
GroupName: aws.String(d.Get("placement_group").(string)),
}

if v, ok := d.GetOk("placement_partition_number"); ok {
opts.Placement.PartitionNumber = aws.Int64(int64(v.(int)))
}

opts.SpotPlacement = &ec2.SpotPlacement{
AvailabilityZone: aws.String(d.Get("availability_zone").(string)),
GroupName: aws.String(d.Get("placement_group").(string)),
Expand Down
64 changes: 63 additions & 1 deletion aws/resource_aws_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ func TestAccAWSInstance_outpost(t *testing.T) {
func TestAccAWSInstance_placementGroup(t *testing.T) {
var v ec2.Instance
resourceName := "aws_instance.test"
rName := fmt.Sprintf("tf-testacc-instance-%s", acctest.RandString(12))
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -892,6 +892,34 @@ func TestAccAWSInstance_placementGroup(t *testing.T) {
})
}

func TestAccAWSInstance_placementPartitionNumber(t *testing.T) {
var v ec2.Instance
resourceName := "aws_instance.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccInstanceConfigPlacementPartitionNumber(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "placement_group", rName),
resource.TestCheckResourceAttr(resourceName, "placement_partition_number", "3"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSInstance_ipv6_supportAddressCount(t *testing.T) {
var v ec2.Instance
resourceName := "aws_instance.test"
Expand Down Expand Up @@ -4556,6 +4584,40 @@ resource "aws_instance" "test" {
# pre-encoded base64 data
user_data = "3dc39dda39be1205215e776bad998da361a5955d"
tags = {
Name = %[1]q
}
}
`, rName))
}

func testAccInstanceConfigPlacementPartitionNumber(rName string) string {
return composeConfig(
testAccLatestAmazonLinuxHvmEbsAmiConfig(),
testAccAwsInstanceVpcConfig(rName, false),
fmt.Sprintf(`
resource "aws_placement_group" "test" {
name = %[1]q
strategy = "partition"
partition_count = 4
}
# Limitations: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html#concepts-placement-groups
resource "aws_instance" "test" {
ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id
instance_type = "c5.large"
subnet_id = aws_subnet.test.id
associate_public_ip_address = true
placement_group = aws_placement_group.test.name
placement_partition_number = 3
# pre-encoded base64 data
user_data = "3dc39dda39be1205215e776bad998da361a5955d"
tags = {
Name = %[1]q
}
}
`, rName))
}
Expand Down
Loading

0 comments on commit a4b2dea

Please sign in to comment.