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 #1047

Closed
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 @@ -475,6 +475,7 @@ func Provider() terraform.ResourceProvider {
"aws_waf_sql_injection_match_set": resourceAwsWafSqlInjectionMatchSet(),
"aws_wafregional_byte_match_set": resourceAwsWafRegionalByteMatchSet(),
"aws_wafregional_ipset": resourceAwsWafRegionalIPSet(),
"aws_wafregional_web_acl_association": resourceAwsWafRegionalWebAclAssociation(),
},
ConfigureFunc: providerConfigure,
}
Expand Down
135 changes: 135 additions & 0 deletions aws/resource_aws_wafregional_web_acl_association.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package aws

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

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"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,
Update: resourceAwsWafRegionalWebAclAssociationUpdate,
Delete: resourceAwsWafRegionalWebAclAssociationDelete,

Schema: map[string]*schema.Schema{
"web_acl_id": &schema.Schema{
Type: schema.TypeString,
Required: 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 awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "WAFUnavailableEntityException" {
return resource.RetryableError(awsErr)
}
}
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

web_acl_id, resource_arn := resourceAwsWafRegionalWebAclAssociationParseId(d.Id())

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

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

// Find match
found := false
for _, list_resource_arn := range resp.ResourceArns {
if resource_arn == *list_resource_arn {
found = true
break
}
}
if !found {
// It seems it doesn't exist anymore, so clear the ID
d.SetId("")
}

return nil
}

func resourceAwsWafRegionalWebAclAssociationUpdate(d *schema.ResourceData, meta interface{}) error {
return resourceAwsWafRegionalWebAclAssociationRead(d, meta)
}

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

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

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

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

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

return nil
}

func resourceAwsWafRegionalWebAclAssociationParseId(id string) (web_acl_id, resource_arn string) {
parts := strings.SplitN(id, ":", 2)
web_acl_id = parts[0]
resource_arn = parts[1]
return
}
161 changes: 161 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,161 @@
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/waf"
"github.com/aws/aws-sdk-go/service/wafregional"
)

func TestAccAWSWafRegionalWebAclAssociation_basic(t *testing.T) {
var webAcl waf.WebACL

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckWafRegionalWebAclAssociationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckWafRegionalWebAclAssociationConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.foo", &webAcl),
),
},
},
})
}

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
}

web_acl_id, resource_arn := resourceAwsWafRegionalWebAclAssociationParseId(rs.Primary.ID)

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

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

func testAccCheckWafRegionalWebAclAssociationExistsWithProvider(s *terraform.State, n string, webAcl *waf.WebACL, 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")
}

web_acl_id, resource_arn := resourceAwsWafRegionalWebAclAssociationParseId(rs.Primary.ID)

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

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

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

return nil
}

const testAccCheckWafRegionalWebAclAssociationConfig = `
resource "aws_wafregional_ipset" "foo" {
name = "foo"
ip_set_descriptors {
type = "IPV4"
value = "192.0.7.0/24"
}
}

resource "aws_wafregional_rule" "foo" {
depends_on = ["aws_wafregional_ipset.foo"]
name = "foo"
metric_name = "foo"
predicates {
data_id = "${aws_wafregional_ipset.foo.id}"
negated = false
type = "IPMatch"
}
}

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

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

resource "aws_subnet" "foo" {
vpc_id = "${aws_vpc.foo.id}"
cidr_block = "10.1.1.0/24"
}

resource "aws_subnet" "bar" {
vpc_id = "${aws_vpc.foo.id}"
cidr_block = "10.1.2.0/24"
}

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

resource "aws_wafregional_web_acl_association" "foo" {
depends_on = ["aws_alb.foo", "aws_wafregional_web_acl.foo"]
resource_arn = "${aws_alb.foo.arn}"
web_acl_id = "${aws_wafregional_web_acl.foo.id}"
}
`
4 changes: 4 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,10 @@
<a href="/docs/providers/aws/r/wafregional_ipset.html">aws_wafregional_ipset</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>

</ul>
</li>

Expand Down
Loading