Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: aws_wafregional_web_acl_association #3755

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ func Provider() terraform.ResourceProvider {
"aws_wafregional_xss_match_set": resourceAwsWafRegionalXssMatchSet(),
"aws_wafregional_rule": resourceAwsWafRegionalRule(),
"aws_wafregional_web_acl": resourceAwsWafRegionalWebAcl(),
"aws_wafregional_web_acl_association": resourceAwsWafRegionalWebAclAssociation(),
"aws_batch_compute_environment": resourceAwsBatchComputeEnvironment(),
"aws_batch_job_definition": resourceAwsBatchJobDefinition(),
"aws_batch_job_queue": resourceAwsBatchJobQueue(),
Expand Down
128 changes: 128 additions & 0 deletions aws/resource_aws_wafregional_web_acl_association.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package aws

import (
"fmt"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/wafregional"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsWafRegionalWebAclAssociation() *schema.Resource {
return &schema.Resource{
Create: resourceAwsWafRegionalWebAclAssociationCreate,
Read: resourceAwsWafRegionalWebAclAssociationRead,
Delete: resourceAwsWafRegionalWebAclAssociationDelete,

Schema: map[string]*schema.Schema{
"web_acl_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"resource_arn": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

func resourceAwsWafRegionalWebAclAssociationCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn

log.Printf(
"[INFO] Creating WAF Regional Web ACL association: %s => %s",
d.Get("web_acl_id").(string),
d.Get("resource_arn").(string))

params := &wafregional.AssociateWebACLInput{
WebACLId: aws.String(d.Get("web_acl_id").(string)),
ResourceArn: aws.String(d.Get("resource_arn").(string)),
}

// create association and wait on retryable error
// no response body
var err error
err = resource.Retry(2*time.Minute, func() *resource.RetryError {
_, err = conn.AssociateWebACL(params)
if err != nil {
if isAWSErr(err, wafregional.ErrCodeWAFUnavailableEntityException, "") {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
if err != nil {
return err
}

// Store association id
d.SetId(fmt.Sprintf("%s:%s", *params.WebACLId, *params.ResourceArn))

return nil
}

func resourceAwsWafRegionalWebAclAssociationRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn

webAclId, resourceArn := resourceAwsWafRegionalWebAclAssociationParseId(d.Id())

// List all resources for Web ACL and see if we get a match
params := &wafregional.ListResourcesForWebACLInput{
WebACLId: aws.String(webAclId),
}

resp, err := conn.ListResourcesForWebACL(params)
if err != nil {
return err
}

// Find match
found := false
for _, listResourceArn := range resp.ResourceArns {
if resourceArn == *listResourceArn {
found = true
break
}
}
if !found {
log.Printf("[WARN] WAF Regional Web ACL association (%s) not found, removing from state", d.Id())
d.SetId("")
}

return nil
}

func resourceAwsWafRegionalWebAclAssociationDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn

_, resourceArn := resourceAwsWafRegionalWebAclAssociationParseId(d.Id())

log.Printf("[INFO] Deleting WAF Regional Web ACL association: %s", resourceArn)

params := &wafregional.DisassociateWebACLInput{
ResourceArn: aws.String(resourceArn),
}

// If action successful HTTP 200 response with an empty body
_, err := conn.DisassociateWebACL(params)
if err != nil {
return err
}

return nil
}

func resourceAwsWafRegionalWebAclAssociationParseId(id string) (webAclId, resourceArn string) {
parts := strings.SplitN(id, ":", 2)
webAclId = parts[0]
resourceArn = parts[1]
return
}
177 changes: 177 additions & 0 deletions aws/resource_aws_wafregional_web_acl_association_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package aws

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/wafregional"
)

func TestAccAWSWafRegionalWebAclAssociation_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckWafRegionalWebAclAssociationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckWafRegionalWebAclAssociationConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.foo"),
),
},
},
})
}

func TestAccAWSWafRegionalWebAclAssociation_multipleAssociations(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckWafRegionalWebAclAssociationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckWafRegionalWebAclAssociationConfig_multipleAssociations,
Check: resource.ComposeTestCheckFunc(
testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.foo"),
testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.bar"),
),
},
},
})
}

func testAccCheckWafRegionalWebAclAssociationDestroy(s *terraform.State) error {
return testAccCheckWafRegionalWebAclAssociationDestroyWithProvider(s, testAccProvider)
}

func testAccCheckWafRegionalWebAclAssociationDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
conn := provider.Meta().(*AWSClient).wafregionalconn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_wafregional_web_acl_association" {
continue
}

webAclId, resourceArn := resourceAwsWafRegionalWebAclAssociationParseId(rs.Primary.ID)

resp, err := conn.ListResourcesForWebACL(&wafregional.ListResourcesForWebACLInput{WebACLId: aws.String(webAclId)})
if err != nil {
found := false
for _, listResourceArn := range resp.ResourceArns {
if resourceArn == *listResourceArn {
found = true
break
}
}
if found {
return fmt.Errorf("WebACL: %v is still associated to resource: %v", webAclId, resourceArn)
}
}
}
return nil
}

func testAccCheckWafRegionalWebAclAssociationExists(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
return testAccCheckWafRegionalWebAclAssociationExistsWithProvider(s, n, testAccProvider)
}
}

func testAccCheckWafRegionalWebAclAssociationExistsWithProvider(s *terraform.State, n string, provider *schema.Provider) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No WebACL association ID is set")
}

webAclId, resourceArn := resourceAwsWafRegionalWebAclAssociationParseId(rs.Primary.ID)

conn := provider.Meta().(*AWSClient).wafregionalconn
resp, err := conn.ListResourcesForWebACL(&wafregional.ListResourcesForWebACLInput{WebACLId: aws.String(webAclId)})
if err != nil {
return fmt.Errorf("List Web ACL err: %v", err)
}

found := false
for _, listResourceArn := range resp.ResourceArns {
if resourceArn == *listResourceArn {
found = true
break
}
}

if !found {
return fmt.Errorf("Web ACL association not found")
}

return nil
}

const testAccCheckWafRegionalWebAclAssociationConfig_basic = `
resource "aws_wafregional_rule" "foo" {
name = "foo"
metric_name = "foo"
}

resource "aws_wafregional_web_acl" "foo" {
name = "foo"
metric_name = "foo"
default_action {
type = "ALLOW"
}
rule {
action {
type = "COUNT"
}
priority = 100
rule_id = "${aws_wafregional_rule.foo.id}"
}
}

resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
}

data "aws_availability_zones" "available" {}

resource "aws_subnet" "foo" {
vpc_id = "${aws_vpc.foo.id}"
cidr_block = "10.1.1.0/24"
availability_zone = "${data.aws_availability_zones.available.names[0]}"
}

resource "aws_subnet" "bar" {
vpc_id = "${aws_vpc.foo.id}"
cidr_block = "10.1.2.0/24"
availability_zone = "${data.aws_availability_zones.available.names[1]}"
}

resource "aws_alb" "foo" {
internal = true
subnets = ["${aws_subnet.foo.id}", "${aws_subnet.bar.id}"]
}

resource "aws_wafregional_web_acl_association" "foo" {
resource_arn = "${aws_alb.foo.arn}"
web_acl_id = "${aws_wafregional_web_acl.foo.id}"
}
`

const testAccCheckWafRegionalWebAclAssociationConfig_multipleAssociations = testAccCheckWafRegionalWebAclAssociationConfig_basic + `
resource "aws_alb" "bar" {
internal = true
subnets = ["${aws_subnet.foo.id}", "${aws_subnet.bar.id}"]
}

resource "aws_wafregional_web_acl_association" "bar" {
resource_arn = "${aws_alb.bar.arn}"
web_acl_id = "${aws_wafregional_web_acl.foo.id}"
}
`
5 changes: 5 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -1531,9 +1531,14 @@
<a href="/docs/providers/aws/r/wafregional_web_acl.html">aws_wafregional_web_acl</a>
</li>

<li<%= sidebar_current("docs-aws-resource-wafregional-web-acl-association") %>>
<a href="/docs/providers/aws/r/wafregional_web_acl_association.html">aws_wafregional_web_acl_association</a>
</li>

<li<%= sidebar_current("docs-aws-resource-wafregional-xss-match-set") %>>
<a href="/docs/providers/aws/r/wafregional_xss_match_set.html">aws_wafregional_xss_match_set</a>
</li>

</ul>
</li>

Expand Down
Loading