Skip to content

Commit

Permalink
Merge pull request #1685 from ctiwald/master
Browse files Browse the repository at this point in the history
provider/aws: Implement support for various AWS ELB cookie stickiness policies
  • Loading branch information
mitchellh committed Apr 29, 2015
2 parents 57af67b + d42441f commit d354cae
Show file tree
Hide file tree
Showing 8 changed files with 679 additions and 0 deletions.
2 changes: 2 additions & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func Provider() terraform.ResourceProvider {

ResourcesMap: map[string]*schema.Resource{
"aws_autoscaling_group": resourceAwsAutoscalingGroup(),
"aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(),
"aws_db_instance": resourceAwsDbInstance(),
"aws_db_parameter_group": resourceAwsDbParameterGroup(),
"aws_db_security_group": resourceAwsDbSecurityGroup(),
Expand All @@ -89,6 +90,7 @@ func Provider() terraform.ResourceProvider {
"aws_internet_gateway": resourceAwsInternetGateway(),
"aws_key_pair": resourceAwsKeyPair(),
"aws_launch_configuration": resourceAwsLaunchConfiguration(),
"aws_lb_cookie_stickiness_policy": resourceAwsLBCookieStickinessPolicy(),
"aws_main_route_table_association": resourceAwsMainRouteTableAssociation(),
"aws_network_acl": resourceAwsNetworkAcl(),
"aws_network_interface": resourceAwsNetworkInterface(),
Expand Down
156 changes: 156 additions & 0 deletions builtin/providers/aws/resource_aws_app_cookie_stickiness_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package aws

import (
"fmt"
"strings"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/elb"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsAppCookieStickinessPolicy() *schema.Resource {
return &schema.Resource{
// There is no concept of "updating" an App Stickiness policy in
// the AWS API.
Create: resourceAwsAppCookieStickinessPolicyCreate,
Update: resourceAwsAppCookieStickinessPolicyCreate,

Read: resourceAwsAppCookieStickinessPolicyRead,
Delete: resourceAwsAppCookieStickinessPolicyDelete,

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

"load_balancer": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"lb_port": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},

"cookie_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

func resourceAwsAppCookieStickinessPolicyCreate(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbconn

// Provision the AppStickinessPolicy
acspOpts := &elb.CreateAppCookieStickinessPolicyInput{
CookieName: aws.String(d.Get("cookie_name").(string)),
LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
PolicyName: aws.String(d.Get("name").(string)),
}

if _, err := elbconn.CreateAppCookieStickinessPolicy(acspOpts); err != nil {
return fmt.Errorf("Error creating AppCookieStickinessPolicy: %s", err)
}

setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{
LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
LoadBalancerPort: aws.Long(int64(d.Get("lb_port").(int))),
PolicyNames: []*string{aws.String(d.Get("name").(string))},
}

if _, err := elbconn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil {
return fmt.Errorf("Error setting AppCookieStickinessPolicy: %s", err)
}

d.SetId(fmt.Sprintf("%s:%d:%s",
*acspOpts.LoadBalancerName,
*setLoadBalancerOpts.LoadBalancerPort,
*acspOpts.PolicyName))
return nil
}

func resourceAwsAppCookieStickinessPolicyRead(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbconn

lbName, lbPort, policyName := resourceAwsAppCookieStickinessPolicyParseId(d.Id())

request := &elb.DescribeLoadBalancerPoliciesInput{
LoadBalancerName: aws.String(lbName),
PolicyNames: []*string{aws.String(policyName)},
}

getResp, err := elbconn.DescribeLoadBalancerPolicies(request)
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "PolicyNotFound" {
// The policy is gone.
d.SetId("")
return nil
}
return fmt.Errorf("Error retrieving policy: %s", err)
}

if len(getResp.PolicyDescriptions) != 1 {
return fmt.Errorf("Unable to find policy %#v", getResp.PolicyDescriptions)
}

// We can get away with this because there's only one attribute, the
// cookie expiration, in these descriptions.
policyDesc := getResp.PolicyDescriptions[0]
cookieAttr := policyDesc.PolicyAttributeDescriptions[0]
if *cookieAttr.AttributeName != "CookieName" {
return fmt.Errorf("Unable to find cookie Name.")
}
d.Set("cookie_name", cookieAttr.AttributeValue)

d.Set("name", policyName)
d.Set("load_balancer", lbName)
d.Set("lb_port", lbPort)

return nil
}

func resourceAwsAppCookieStickinessPolicyDelete(d *schema.ResourceData, meta interface{}) error {
elbconn := meta.(*AWSClient).elbconn

lbName, _, policyName := resourceAwsAppCookieStickinessPolicyParseId(d.Id())

// Perversely, if we Set an empty list of PolicyNames, we detach the
// policies attached to a listener, which is required to delete the
// policy itself.
setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{
LoadBalancerName: aws.String(d.Get("load_balancer").(string)),
LoadBalancerPort: aws.Long(int64(d.Get("lb_port").(int))),
PolicyNames: []*string{},
}

if _, err := elbconn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil {
return fmt.Errorf("Error removing AppCookieStickinessPolicy: %s", err)
}

request := &elb.DeleteLoadBalancerPolicyInput{
LoadBalancerName: aws.String(lbName),
PolicyName: aws.String(policyName),
}

if _, err := elbconn.DeleteLoadBalancerPolicy(request); err != nil {
return fmt.Errorf("Error deleting App stickiness policy %s: %s", d.Id(), err)
}
return nil
}

// resourceAwsAppCookieStickinessPolicyParseId takes an ID and parses it into
// it's constituent parts. You need three axes (LB name, policy name, and LB
// port) to create or identify a stickiness policy in AWS's API.
func resourceAwsAppCookieStickinessPolicyParseId(id string) (string, string, string) {
parts := strings.SplitN(id, ":", 3)
return parts[0], parts[1], parts[2]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package aws

import (
"fmt"
"testing"

"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/service/elb"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSAppCookieStickinessPolicy(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAppCookieStickinessPolicyDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAppCookieStickinessPolicyConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAppCookieStickinessPolicy(
"aws_elb.lb",
"aws_app_cookie_stickiness_policy.foo",
),
),
},
resource.TestStep{
Config: testAccAppCookieStickinessPolicyConfigUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckAppCookieStickinessPolicy(
"aws_elb.lb",
"aws_app_cookie_stickiness_policy.bar",
),
),
},
},
})
}

func testAccCheckAppCookieStickinessPolicyDestroy(s *terraform.State) error {
if len(s.RootModule().Resources) > 0 {
return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources)
}

return nil
}

func testAccCheckAppCookieStickinessPolicy(elbResource string, policyResource string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[elbResource]
if !ok {
return fmt.Errorf("Not found: %s", elbResource)
}

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

policy, ok := s.RootModule().Resources[policyResource]
if !ok {
return fmt.Errorf("Not found: %s", policyResource)
}

elbconn := testAccProvider.Meta().(*AWSClient).elbconn
elbName, _, policyName := resourceAwsAppCookieStickinessPolicyParseId(policy.Primary.ID)
_, err := elbconn.DescribeLoadBalancerPolicies(&elb.DescribeLoadBalancerPoliciesInput{
LoadBalancerName: aws.String(elbName),
PolicyNames: []*string{aws.String(policyName)},
})

if err != nil {
return err
}

return nil
}
}

const testAccAppCookieStickinessPolicyConfig = `
resource "aws_elb" "lb" {
name = "test-lb"
availability_zones = ["us-east-1a"]
listener {
instance_port = 8000
instance_protocol = "http"
lb_port = 80
lb_protocol = "http"
}
}
resource "aws_app_cookie_stickiness_policy" "foo" {
name = "foo_policy"
load_balancer = "${aws_elb.lb}"
lb_port = 80
cookie_name = "MyAppCookie"
}
`

const testAccAppCookieStickinessPolicyConfigUpdate = `
resource "aws_elb" "lb" {
name = "test-lb"
availability_zones = ["us-east-1a"]
listener {
instance_port = 8000
instance_protocol = "http"
lb_port = 80
lb_protocol = "http"
}
}
resource "aws_app_cookie_stickiness_policy" "foo" {
name = "foo_policy"
load_balancer = "${aws_elb.lb}"
lb_port = 80
cookie_name = "MyAppCookie"
}
resource "aws_app_cookie_stickiness_policy" "bar" {
name = "bar_policy"
load_balancer = "${aws_elb.lb}"
lb_port = 80
cookie_name = "MyAppCookie"
}
`
Loading

0 comments on commit d354cae

Please sign in to comment.