diff --git a/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy.go b/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy.go index 2b25064c5..ecdc8eff4 100644 --- a/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy.go +++ b/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy.go @@ -2,7 +2,9 @@ package aws import ( "fmt" + "log" "regexp" + "strconv" "strings" "github.com/aws/aws-sdk-go/aws" @@ -106,11 +108,22 @@ func resourceAwsAppCookieStickinessPolicyRead(d *schema.ResourceData, meta inter } return fmt.Errorf("Error retrieving policy: %s", err) } - if len(getResp.PolicyDescriptions) != 1 { return fmt.Errorf("Unable to find policy %#v", getResp.PolicyDescriptions) } + // we know the policy exists now, but we have to check if it's assigned to a listener + assigned, err := resourceAwsELBSticknessPolicyAssigned(policyName, lbName, lbPort, elbconn) + if err != nil { + return err + } + if !assigned { + // policy exists, but isn't assigned to a listener + log.Printf("[DEBUG] policy '%s' exists, but isn't assigned to a listener", policyName) + d.SetId("") + return nil + } + // We can get away with this because there's only one attribute, the // cookie expiration, in these descriptions. policyDesc := getResp.PolicyDescriptions[0] @@ -127,6 +140,43 @@ func resourceAwsAppCookieStickinessPolicyRead(d *schema.ResourceData, meta inter return nil } +// Determine if a particular policy is assigned to an ELB listener +func resourceAwsELBSticknessPolicyAssigned(policyName, lbName, lbPort string, elbconn *elb.ELB) (bool, error) { + describeElbOpts := &elb.DescribeLoadBalancersInput{ + LoadBalancerNames: []*string{aws.String(lbName)}, + } + describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts) + if err != nil { + if ec2err, ok := err.(awserr.Error); ok { + if ec2err.Code() == "LoadBalancerNotFound" { + return false, nil + } + } + return false, fmt.Errorf("Error retrieving ELB description: %s", err) + } + + if len(describeResp.LoadBalancerDescriptions) != 1 { + return false, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancerDescriptions) + } + + lb := describeResp.LoadBalancerDescriptions[0] + assigned := false + for _, listener := range lb.ListenerDescriptions { + if lbPort != strconv.Itoa(int(*listener.Listener.LoadBalancerPort)) { + continue + } + + for _, name := range listener.PolicyNames { + if policyName == *name { + assigned = true + break + } + } + } + + return assigned, nil +} + func resourceAwsAppCookieStickinessPolicyDelete(d *schema.ResourceData, meta interface{}) error { elbconn := meta.(*AWSClient).elbconn diff --git a/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy_test.go b/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy_test.go index 5b2bd3612..ed0d25a46 100644 --- a/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy_test.go +++ b/builtin/providers/aws/resource_aws_app_cookie_stickiness_policy_test.go @@ -139,6 +139,54 @@ func testAccCheckAppCookieStickinessPolicy(elbResource string, policyResource st } } +// ensure the policy is re-added is it goes missing +func TestAccAWSAppCookieStickinessPolicy_drift(t *testing.T) { + lbName := fmt.Sprintf("tf-test-lb-%s", acctest.RandString(5)) + + // We only want to remove the reference to the policy from the listner, + // beacause that's all that can be done via the console. + removePolicy := func() { + conn := testAccProvider.Meta().(*AWSClient).elbconn + + setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{ + LoadBalancerName: aws.String(lbName), + LoadBalancerPort: aws.Int64(80), + PolicyNames: []*string{}, + } + + if _, err := conn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil { + t.Fatalf("Error removing AppCookieStickinessPolicy: %s", err) + } + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppCookieStickinessPolicyDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAppCookieStickinessPolicyConfig(lbName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppCookieStickinessPolicy( + "aws_elb.lb", + "aws_app_cookie_stickiness_policy.foo", + ), + ), + }, + resource.TestStep{ + PreConfig: removePolicy, + Config: testAccAppCookieStickinessPolicyConfig(lbName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppCookieStickinessPolicy( + "aws_elb.lb", + "aws_app_cookie_stickiness_policy.foo", + ), + ), + }, + }, + }) +} + func testAccAppCookieStickinessPolicyConfig(rName string) string { return fmt.Sprintf(` resource "aws_elb" "lb" { diff --git a/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy.go b/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy.go index ea2215b6a..6ef5042bf 100644 --- a/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy.go +++ b/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy.go @@ -115,6 +115,18 @@ func resourceAwsLBCookieStickinessPolicyRead(d *schema.ResourceData, meta interf return fmt.Errorf("Unable to find policy %#v", getResp.PolicyDescriptions) } + // we know the policy exists now, but we have to check if it's assigned to a listener + assigned, err := resourceAwsELBSticknessPolicyAssigned(policyName, lbName, lbPort, elbconn) + if err != nil { + return err + } + if !assigned { + // policy exists, but isn't assigned to a listener + log.Printf("[DEBUG] policy '%s' exists, but isn't assigned to a listener", policyName) + d.SetId("") + return nil + } + // We can get away with this because there's only one attribute, the // cookie expiration, in these descriptions. policyDesc := getResp.PolicyDescriptions[0] diff --git a/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy_test.go b/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy_test.go index 088848a13..877e49b76 100644 --- a/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy_test.go +++ b/builtin/providers/aws/resource_aws_lb_cookie_stickiness_policy_test.go @@ -102,6 +102,53 @@ func testAccCheckLBCookieStickinessPolicy(elbResource string, policyResource str } } +func TestAccCheckLBCookieStickinessPolicy_drift(t *testing.T) { + lbName := fmt.Sprintf("tf-test-lb-%s", acctest.RandString(5)) + + // We only want to remove the reference to the policy from the listner, + // beacause that's all that can be done via the console. + removePolicy := func() { + conn := testAccProvider.Meta().(*AWSClient).elbconn + + setLoadBalancerOpts := &elb.SetLoadBalancerPoliciesOfListenerInput{ + LoadBalancerName: aws.String(lbName), + LoadBalancerPort: aws.Int64(80), + PolicyNames: []*string{}, + } + + if _, err := conn.SetLoadBalancerPoliciesOfListener(setLoadBalancerOpts); err != nil { + t.Fatalf("Error removing LBCookieStickinessPolicy: %s", err) + } + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLBCookieStickinessPolicyDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccLBCookieStickinessPolicyConfig(lbName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLBCookieStickinessPolicy( + "aws_elb.lb", + "aws_lb_cookie_stickiness_policy.foo", + ), + ), + }, + resource.TestStep{ + PreConfig: removePolicy, + Config: testAccLBCookieStickinessPolicyConfig(lbName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLBCookieStickinessPolicy( + "aws_elb.lb", + "aws_lb_cookie_stickiness_policy.foo", + ), + ), + }, + }, + }) +} + func testAccLBCookieStickinessPolicyConfig(rName string) string { return fmt.Sprintf(` resource "aws_elb" "lb" {