-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21993 from csabakollar/f/shield_protection_health…
…_check_association New Resource: aws_shield_protection_health_check_association
- Loading branch information
Showing
6 changed files
with
423 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:new-resource | ||
resource/aws_shield_protection_health_check_association | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package shield | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
const protectionHealthCheckAssociationResourceIDSeparator = "+" | ||
|
||
func ProtectionHealthCheckAssociationCreateResourceID(protectionId, healthCheckArn string) string { | ||
parts := []string{protectionId, healthCheckArn} | ||
id := strings.Join(parts, protectionHealthCheckAssociationResourceIDSeparator) | ||
|
||
return id | ||
} | ||
|
||
func ProtectionHealthCheckAssociationParseResourceID(id string) (string, string, error) { | ||
parts := strings.Split(id, protectionHealthCheckAssociationResourceIDSeparator) | ||
|
||
if len(parts) == 2 && parts[0] != "" && parts[1] != "" { | ||
return parts[0], parts[1], nil | ||
} | ||
|
||
return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected PROTECTIONID%[2]sHEALTHCHECKARN", id, protectionHealthCheckAssociationResourceIDSeparator) | ||
} |
125 changes: 125 additions & 0 deletions
125
internal/service/shield/protection_health_check_association.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package shield | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/shield" | ||
"github.com/hashicorp/aws-sdk-go-base/tfawserr" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/hashicorp/terraform-provider-aws/internal/conns" | ||
) | ||
|
||
func ResourceProtectionHealthCheckAssociation() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: ResourceProtectionHealthCheckAssociationCreate, | ||
Read: ResourceProtectionHealthCheckAssociationRead, | ||
Delete: ResourceProtectionHealthCheckAssociationDelete, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"shield_protection_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"health_check_arn": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func ResourceProtectionHealthCheckAssociationCreate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*conns.AWSClient).ShieldConn | ||
|
||
protectionId := d.Get("shield_protection_id").(string) | ||
healthCheckArn := d.Get("health_check_arn").(string) | ||
id := ProtectionHealthCheckAssociationCreateResourceID(protectionId, healthCheckArn) | ||
|
||
input := &shield.AssociateHealthCheckInput{ | ||
ProtectionId: aws.String(protectionId), | ||
HealthCheckArn: aws.String(healthCheckArn), | ||
} | ||
|
||
_, err := conn.AssociateHealthCheck(input) | ||
if err != nil { | ||
return fmt.Errorf("error associating Route53 Health Check (%s) with Shield Protected resource (%s): %s", d.Get("health_check_arn"), d.Get("shield_protection_id"), err) | ||
} | ||
d.SetId(id) | ||
return ResourceProtectionHealthCheckAssociationRead(d, meta) | ||
} | ||
|
||
func ResourceProtectionHealthCheckAssociationRead(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*conns.AWSClient).ShieldConn | ||
|
||
protectionId, healthCheckArn, err := ProtectionHealthCheckAssociationParseResourceID(d.Id()) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error parsing Shield Protection and Route53 Health Check Association ID: %w", err) | ||
} | ||
|
||
input := &shield.DescribeProtectionInput{ | ||
ProtectionId: aws.String(protectionId), | ||
} | ||
|
||
resp, err := conn.DescribeProtection(input) | ||
|
||
if tfawserr.ErrMessageContains(err, shield.ErrCodeResourceNotFoundException, "") { | ||
log.Printf("[WARN] Shield Protection itself (%s) not found, removing from state", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
if err != nil { | ||
return fmt.Errorf("error reading Shield Protection Health Check Association (%s): %s", d.Id(), err) | ||
} | ||
|
||
isHealthCheck := stringInSlice(strings.Split(healthCheckArn, "/")[1], aws.StringValueSlice(resp.Protection.HealthCheckIds)) | ||
if !isHealthCheck { | ||
log.Printf("[WARN] Shield Protection Health Check Association (%s) not found, removing from state", d.Id()) | ||
d.SetId("") | ||
} | ||
|
||
d.Set("health_check_arn", healthCheckArn) | ||
d.Set("shield_protection_id", resp.Protection.Id) | ||
|
||
return nil | ||
} | ||
|
||
func ResourceProtectionHealthCheckAssociationDelete(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*conns.AWSClient).ShieldConn | ||
|
||
protectionId, healthCheckId, err := ProtectionHealthCheckAssociationParseResourceID(d.Id()) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error parsing Shield Protection and Route53 Health Check Association ID: %w", err) | ||
} | ||
|
||
input := &shield.DisassociateHealthCheckInput{ | ||
ProtectionId: aws.String(protectionId), | ||
HealthCheckArn: aws.String(healthCheckId), | ||
} | ||
|
||
_, err = conn.DisassociateHealthCheck(input) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error disassociating Route53 Health Check (%s) from Shield Protected resource (%s): %s", d.Get("health_check_arn"), d.Get("shield_protection_id"), err) | ||
} | ||
return nil | ||
} | ||
|
||
func stringInSlice(expected string, list []string) bool { | ||
for _, item := range list { | ||
if item == expected { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
192 changes: 192 additions & 0 deletions
192
internal/service/shield/protection_health_check_association_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
package shield_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/shield" | ||
"github.com/hashicorp/aws-sdk-go-base/tfawserr" | ||
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
"github.com/hashicorp/terraform-provider-aws/internal/acctest" | ||
"github.com/hashicorp/terraform-provider-aws/internal/conns" | ||
tfshield "github.com/hashicorp/terraform-provider-aws/internal/service/shield" | ||
) | ||
|
||
func TestAccShieldProtectionHealthCheckAssociation_basic(t *testing.T) { | ||
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) | ||
resourceName := "aws_shield_protection_health_check_association.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { | ||
acctest.PreCheck(t) | ||
acctest.PreCheckPartitionHasService(shield.EndpointsID, t) | ||
testAccPreCheck(t) | ||
}, | ||
ErrorCheck: acctest.ErrorCheck(t, shield.EndpointsID), | ||
Providers: acctest.Providers, | ||
CheckDestroy: testAccCheckAWSShieldProtectionHealthCheckAssociationDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccShieldProtectionaHealthCheckAssociationConfig(rName), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSShieldProtectionHealthCheckAssociationExists(resourceName), | ||
), | ||
}, | ||
{ | ||
ResourceName: resourceName, | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccShieldProtectionHealthCheckAssociation_disappears(t *testing.T) { | ||
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) | ||
resourceName := "aws_shield_protection_health_check_association.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { | ||
acctest.PreCheck(t) | ||
acctest.PreCheckPartitionHasService(shield.EndpointsID, t) | ||
testAccPreCheck(t) | ||
}, | ||
ErrorCheck: acctest.ErrorCheck(t, shield.EndpointsID), | ||
Providers: acctest.Providers, | ||
CheckDestroy: testAccCheckAWSShieldProtectionHealthCheckAssociationDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccShieldProtectionaHealthCheckAssociationConfig(rName), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSShieldProtectionHealthCheckAssociationExists(resourceName), | ||
acctest.CheckResourceDisappears(acctest.Provider, tfshield.ResourceProtectionHealthCheckAssociation(), resourceName), | ||
), | ||
ExpectNonEmptyPlan: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAWSShieldProtectionHealthCheckAssociationDestroy(s *terraform.State) error { | ||
conn := acctest.Provider.Meta().(*conns.AWSClient).ShieldConn | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "aws_shield_protection_health_check_association" { | ||
continue | ||
} | ||
|
||
protectionId, _, err := tfshield.ProtectionHealthCheckAssociationParseResourceID(rs.Primary.ID) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
input := &shield.DescribeProtectionInput{ | ||
ProtectionId: aws.String(protectionId), | ||
} | ||
|
||
resp, err := conn.DescribeProtection(input) | ||
|
||
if tfawserr.ErrMessageContains(err, shield.ErrCodeResourceNotFoundException, "") { | ||
continue | ||
} | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
if resp != nil && resp.Protection != nil && len(aws.StringValueSlice(resp.Protection.HealthCheckIds)) == 0 { | ||
return fmt.Errorf("The Shield protection HealthCheck with IDs %v still exists", aws.StringValueSlice(resp.Protection.HealthCheckIds)) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccCheckAWSShieldProtectionHealthCheckAssociationExists(resourceName string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[resourceName] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", resourceName) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("No Shield Protection and Route53 Health Check Association ID is set") | ||
} | ||
|
||
protectionId, _, err := tfshield.ProtectionHealthCheckAssociationParseResourceID(rs.Primary.ID) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
conn := acctest.Provider.Meta().(*conns.AWSClient).ShieldConn | ||
|
||
input := &shield.DescribeProtectionInput{ | ||
ProtectionId: aws.String(protectionId), | ||
} | ||
|
||
resp, err := conn.DescribeProtection(input) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
if resp == nil || resp.Protection == nil { | ||
return fmt.Errorf("The Shield protection does not exist") | ||
} | ||
|
||
if resp.Protection.HealthCheckIds == nil || len(aws.StringValueSlice(resp.Protection.HealthCheckIds)) != 1 { | ||
return fmt.Errorf("The Shield protection HealthCheck does not exist") | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccShieldProtectionaHealthCheckAssociationConfig(rName string) string { | ||
return fmt.Sprintf(` | ||
data "aws_availability_zones" "available" { | ||
state = "available" | ||
filter { | ||
name = "opt-in-status" | ||
values = ["opt-in-not-required"] | ||
} | ||
} | ||
data "aws_region" "current" {} | ||
data "aws_caller_identity" "current" {} | ||
data "aws_partition" "current" {} | ||
resource "aws_eip" "test" { | ||
vpc = true | ||
tags = { | ||
foo = "bar" | ||
Name = %[1]q | ||
} | ||
} | ||
resource "aws_shield_protection" "test" { | ||
name = %[1]q | ||
resource_arn = "arn:${data.aws_partition.current.partition}:ec2:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:eip-allocation/${aws_eip.test.id}" | ||
} | ||
resource "aws_route53_health_check" "test" { | ||
fqdn = "example.com" | ||
port = 80 | ||
type = "HTTP" | ||
resource_path = "/" | ||
failure_threshold = "5" | ||
request_interval = "30" | ||
tags = { | ||
Name = "tf-test-health-check" | ||
} | ||
} | ||
resource "aws_shield_protection_health_check_association" "test" { | ||
shield_protection_id = aws_shield_protection.test.id | ||
health_check_arn = aws_route53_health_check.test.arn | ||
} | ||
`, rName) | ||
} |
Oops, something went wrong.